home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / vim / src / cmdline.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  83KB  |  3,724 lines

  1. /* vi:ts=4:sw=4
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *
  5.  * Read the file "credits.txt" for a list of people who contributed.
  6.  * Read the file "uganda.txt" for copying and usage conditions.
  7.  */
  8.  
  9. /*
  10.  * cmdline.c: functions for reading in the command line and executing it
  11.  */
  12.  
  13. #include "vim.h"
  14. #include "globals.h"
  15. #include "proto.h"
  16. #include "param.h"
  17. #include "cmdtab.h"
  18. #include "ops.h"            /* included because we call functions in ops.c */
  19. #include "fcntl.h"            /* for chdir() */
  20.  
  21. /*
  22.  * variables shared between getcmdline() and redrawcmdline()
  23.  */
  24. static int         cmdlen;        /* number of chars on command line */
  25. static int         cmdpos;        /* current cursor position */
  26. static int         cmdspos;        /* cursor column on screen */
  27. static int         cmdfirstc;     /* ':', '/' or '?' */
  28. static char_u    *cmdbuff;        /* pointer to command line buffer */
  29.  
  30. /*
  31.  * The next two variables contain the bounds of any range given in a command.
  32.  * They are set by docmdline().
  33.  */
  34. static linenr_t     line1, line2;
  35.  
  36. static int            forceit;
  37. static int            regname;
  38. static int            quitmore = 0;
  39. static int          cmd_numfiles = -1;      /* number of files found by
  40.                                                     filename completion */
  41.  
  42. static void        putcmdline __ARGS((int, char_u *));
  43. static void        cursorcmd __ARGS((void));
  44. static int        ccheck_abbr __ARGS((int));
  45. static char_u    *DoOneCmd __ARGS((char_u *));
  46. static int        buf_write_all __ARGS((BUF *));
  47. static int        dowrite __ARGS((char_u *, int));
  48. static char_u    *getargcmd __ARGS((char_u **));
  49. static char_u    *checknextcomm __ARGS((char_u *));
  50. static void        domake __ARGS((char_u *));
  51. static int        doarglist __ARGS((char_u *));
  52. static int        check_readonly __ARGS((void));
  53. static int        check_changed __ARGS((BUF *, int, int));
  54. static int        check_changed_any __ARGS((int));
  55. static int        check_more __ARGS((int));
  56. #ifdef WEBB_COMPLETE
  57. static void        vim_strncpy __ARGS((char_u *, char_u *, int));
  58. static int        nextwild __ARGS((char_u *, int));
  59. static int        showmatches __ARGS((char_u *));
  60. static void        set_expand_context __ARGS((int, char_u *));
  61. static char_u    *set_one_cmd_context __ARGS((int, char_u *));
  62. static int        ExpandFromContext __ARGS((char_u *, int *, char_u ***, int, int));
  63. #else
  64. static void        nextwild __ARGS((char_u *, int));
  65. static void        showmatches __ARGS((char_u *, int));
  66. #endif /* WEBB_COMPLETE */
  67. static char_u    *addstar __ARGS((char_u *, int));
  68. static linenr_t get_address __ARGS((char_u **));
  69.  
  70. /*
  71.  * getcmdline() - accept a command line starting with ':', '!', '/', or '?'
  72.  *
  73.  * For searches the optional matching '?' or '/' is removed.
  74.  *
  75.  * Return OK if there is a commandline, FAIL if not
  76.  */
  77.  
  78.     int
  79. getcmdline(firstc, buff)
  80.     int            firstc;     /* either ':', '/', or '?' */
  81.     char_u        *buff;         /* buffer for command string */
  82. {
  83.     register char_u     c;
  84.              int        cc;
  85.              int        nextc = 0;
  86.     register int        i;
  87.              int        retval;
  88.              int        hiscnt;                /* current history line in use */
  89.     static     char_u        **history = NULL;    /* history table */
  90.     static     int        hislen = 0;         /* actual lengt of history table */
  91.              int        newlen;                /* new length of history table */
  92.     static     int        hisidx = -1;        /* last entered entry */
  93.              char_u        **temp;
  94.              char_u        *lookfor = NULL;    /* string to match */
  95.              int        j = -1;
  96.              int        gotesc = FALSE;        /* TRUE when last char typed was <ESC> */
  97.              int        do_abbr;            /* when TRUE check for abbr. */
  98.  
  99. /*
  100.  * set some variables for redrawcmd()
  101.  */
  102.     cmdfirstc = firstc;
  103.     cmdbuff = buff;
  104.     cmdlen = cmdpos = 0;
  105.     cmdspos = 1;
  106.     State = CMDLINE;
  107.     gotocmdline(TRUE, firstc);
  108.  
  109. /*
  110.  * if size of history table changed, reallocate it
  111.  */
  112.     newlen = (int)p_hi;
  113.     if (newlen != hislen)                        /* history length changed */
  114.     {
  115.         if (newlen)
  116.             temp = (char_u **)lalloc((long_u)(newlen * sizeof(char_u *)), TRUE);
  117.         else
  118.             temp = NULL;
  119.         if (newlen == 0 || temp != NULL)
  120.         {
  121.             if (newlen > hislen)            /* array becomes bigger */
  122.             {
  123.                 for (i = 0; i <= hisidx; ++i)
  124.                     temp[i] = history[i];
  125.                 j = i;
  126.                 for ( ; i <= newlen - (hislen - hisidx); ++i)
  127.                     temp[i] = NULL;
  128.                 for ( ; j < hislen; ++i, ++j)
  129.                     temp[i] = history[j];
  130.             }
  131.             else                            /* array becomes smaller */
  132.             {
  133.                 j = hisidx;
  134.                 for (i = newlen - 1; ; --i)
  135.                 {
  136.                     if (i >= 0)
  137.                         temp[i] = history[j];    /* copy newest entries */
  138.                     else
  139.                         free(history[j]);        /* remove older entries */
  140.                     if (--j < 0)
  141.                         j = hislen - 1;
  142.                     if (j == hisidx)
  143.                         break;
  144.                 }
  145.                 hisidx = newlen - 1;
  146.             }
  147.             free(history);
  148.             history = temp;
  149.             hislen = newlen;
  150.         }
  151.     }
  152.     hiscnt = hislen;            /* set hiscnt to impossible history value */
  153.  
  154. #ifdef DIGRAPHS
  155.     dodigraph(-1);                /* init digraph typahead */
  156. #endif
  157.  
  158.     /* collect the command string, handling '\b', @ and much more */
  159.     for (;;)
  160.     {
  161.         cursorcmd();    /* set the cursor on the right spot */
  162.         if (nextc)        /* character remaining from CTRL-V */
  163.         {
  164.             c = nextc;
  165.             nextc = 0;
  166.         }
  167.         else
  168.         {
  169.             c = vgetc();
  170.             if (c == Ctrl('C'))
  171.                 got_int = FALSE;
  172.         }
  173.  
  174.         if (lookfor && c != K_SDARROW && c != K_SUARROW)
  175.         {
  176.             free(lookfor);
  177.             lookfor = NULL;
  178.         }
  179.  
  180.         if (cmd_numfiles != -1 && !(c == p_wc && KeyTyped) && c != Ctrl('N') &&
  181.                         c != Ctrl('P') && c != Ctrl('A') && c != Ctrl('L'))
  182.             (void)ExpandOne(NULL, FALSE, -2);    /* may free expanded file names */
  183.  
  184. #ifdef DIGRAPHS
  185.         c = dodigraph(c);
  186. #endif
  187.  
  188.         if (c == '\n' || c == '\r' || (c == ESC && !KeyTyped))
  189.         {
  190.             if (ccheck_abbr(c + 0x100))
  191.                 continue;
  192.             outchar('\r');        /* show that we got the return */
  193.             flushbuf();
  194.             break;
  195.         }
  196.  
  197.             /* hitting <ESC> twice means: abandon command line */
  198.             /* wildcard expansion is only done when the key is really typed, not
  199.                when it comes from a macro */
  200.         if (c == p_wc && !gotesc && KeyTyped)
  201.         {
  202. #ifdef WEBB_COMPLETE
  203.             if (cmd_numfiles > 0)    /* typed p_wc twice */
  204.                 i = nextwild(buff, 3);
  205.             else                    /* typed p_wc first time */
  206.                 i = nextwild(buff, 0);
  207.             if (c == ESC)
  208.                 gotesc = TRUE;
  209.             if (i)
  210.                 continue;
  211. #else
  212.             if (cmd_numfiles > 0)    /* typed p_wc twice */
  213.                 nextwild(buff, 3);
  214.             else                    /* typed p_wc first time */
  215.                 nextwild(buff, 0);
  216.             if (c == ESC)
  217.                 gotesc = TRUE;
  218.             continue;
  219. #endif /* WEBB_COMPLETE */
  220.         }
  221.         gotesc = FALSE;
  222.  
  223.         if (c == K_ZERO)        /* NUL is stored as NL */
  224.             c = '\n';
  225.  
  226.         do_abbr = TRUE;            /* default: check for abbreviation */
  227.         switch (c)
  228.         {
  229.         case BS:
  230.         case DEL:
  231.         case Ctrl('W'):
  232.                 /*
  233.                  * delete current character is the same as backspace on next
  234.                  * character, except at end of line
  235.                  */
  236.                 if (c == DEL && cmdpos != cmdlen)
  237.                     ++cmdpos;
  238.                 if (cmdpos > 0)
  239.                 {
  240.                     j = cmdpos;
  241.                     if (c == Ctrl('W'))
  242.                     {
  243.                         while (cmdpos && isspace(buff[cmdpos - 1]))
  244.                             --cmdpos;
  245.                         i = isidchar(buff[cmdpos - 1]);
  246.                         while (cmdpos && !isspace(buff[cmdpos - 1]) && isidchar(buff[cmdpos - 1]) == i)
  247.                             --cmdpos;
  248.                     }
  249.                     else
  250.                         --cmdpos;
  251.                     cmdlen -= j - cmdpos;
  252.                     i = cmdpos;
  253.                     while (i < cmdlen)
  254.                         buff[i++] = buff[j++];
  255.                     redrawcmd();
  256.                 }
  257.                 else if (cmdlen == 0 && c != Ctrl('W'))
  258.                 {
  259.                     retval = FAIL;
  260.                     msg_pos(-1, 0);
  261.                     msg_outchar(' ');    /* delete ':' */
  262.                     goto returncmd;     /* back to cmd mode */
  263.                 }
  264.                 continue;
  265.  
  266. /*        case '@':    only in very old vi */
  267.         case Ctrl('U'):
  268. clearline:
  269.                 cmdpos = 0;
  270.                 cmdlen = 0;
  271.                 cmdspos = 1;
  272.                 redrawcmd();
  273.                 continue;
  274.  
  275.         case ESC:            /* get here if p_wc != ESC or when ESC typed twice */
  276.         case Ctrl('C'):
  277. do_esc:
  278.                 retval = FAIL;
  279.                 MSG("");
  280.                 goto returncmd;     /* back to cmd mode */
  281.  
  282.         case Ctrl('D'):
  283.             {
  284. #ifdef WEBB_COMPLETE
  285.                 /* set_expand_context() now finds start of the pattern, so
  286.                  * don't do it here -- webb
  287.                  */
  288.                 if (showmatches(buff) == FAIL)
  289.                     break;        /* Use ^D as normal char instead */
  290. #else
  291.                 for (i = cmdpos; i > 0 && buff[i - 1] != ' '; --i)
  292.                         ;
  293.                 showmatches(&buff[i], cmdpos - i);
  294. #endif /* WEBB_COMPLETE */
  295.  
  296.                 redrawcmd();
  297.                 continue;
  298.             }
  299.  
  300.         case K_RARROW:
  301.         case K_SRARROW:
  302.                 do
  303.                 {
  304.                         if (cmdpos >= cmdlen)
  305.                                 break;
  306.                         cmdspos += charsize(buff[cmdpos]);
  307.                         ++cmdpos;
  308.                 }
  309.                 while (c == K_SRARROW && buff[cmdpos] != ' ');
  310.                 continue;
  311.  
  312.         case K_LARROW:
  313.         case K_SLARROW:
  314.                 do
  315.                 {
  316.                         if (cmdpos <= 0)
  317.                                 break;
  318.                         --cmdpos;
  319.                         cmdspos -= charsize(buff[cmdpos]);
  320.                 }
  321.                 while (c == K_SLARROW && buff[cmdpos - 1] != ' ');
  322.                 continue;
  323.  
  324.         case Ctrl('B'):        /* begin of command line */
  325.                 cmdpos = 0;
  326.                 cmdspos = 1;
  327.                 continue;
  328.  
  329.         case Ctrl('E'):        /* end of command line */
  330.                 cmdpos = cmdlen;
  331.                 buff[cmdlen] = NUL;
  332.                 cmdspos = strsize(buff) + 1;
  333.                 continue;
  334.  
  335.         case Ctrl('A'):        /* all matches */
  336. #ifdef WEBB_COMPLETE
  337.                 if (!nextwild(buff, 4))
  338.                     break;
  339. #else
  340.                 nextwild(buff, 4);
  341. #endif /* WEBB_COMPLETE */
  342.                 continue;
  343.  
  344.         case Ctrl('L'):        /* longest common part */
  345. #ifdef WEBB_COMPLETE
  346.                 if (!nextwild(buff, 5))
  347.                     break;
  348. #else
  349.                 nextwild(buff, 5);
  350. #endif /* WEBB_COMPLETE */
  351.                 continue;
  352.  
  353.         case Ctrl('N'):        /* next match */
  354.         case Ctrl('P'):        /* previous match */
  355.                 if (cmd_numfiles > 0)
  356.                 {
  357. #ifdef WEBB_COMPLETE
  358.                     if (!nextwild(buff, (c == Ctrl('P')) ? 2 : 1))
  359.                         break;
  360. #else
  361.                     nextwild(buff, (c == Ctrl('P')) ? 2 : 1);
  362. #endif /* WEBB_COMPLETE */
  363.                     continue;
  364.                 }
  365.  
  366.         case K_UARROW:
  367.         case K_DARROW:
  368.         case K_SUARROW:
  369.         case K_SDARROW:
  370.                 if (hislen == 0)        /* no history */
  371.                     continue;
  372.  
  373.                 i = hiscnt;
  374.             
  375.                     /* save current command string */
  376.                 if (c == K_SUARROW || c == K_SDARROW)
  377.                 {
  378.                     buff[cmdpos] = NUL;
  379.                     if (lookfor == NULL && (lookfor = strsave(buff)) == NULL)
  380.                         continue;
  381.  
  382.                     j = STRLEN(lookfor);
  383.                 }
  384.                 for (;;)
  385.                 {
  386.                         /* one step backwards */
  387.                     if (c == K_UARROW || c == K_SUARROW || c == Ctrl('P'))
  388.                     {
  389.                         if (hiscnt == hislen)    /* first time */
  390.                             hiscnt = hisidx;
  391.                         else if (hiscnt == 0 && hisidx != hislen - 1)
  392.                             hiscnt = hislen - 1;
  393.                         else if (hiscnt != hisidx + 1)
  394.                             --hiscnt;
  395.                         else                    /* at top of list */
  396.                             break;
  397.                     }
  398.                     else    /* one step forwards */
  399.                     {
  400.                         if (hiscnt == hisidx)    /* on last entry, clear the line */
  401.                         {
  402.                             hiscnt = hislen;
  403.                             goto clearline;
  404.                         }
  405.                         if (hiscnt == hislen)    /* not on a history line, nothing to do */
  406.                             break;
  407.                         if (hiscnt == hislen - 1)    /* wrap around */
  408.                             hiscnt = 0;
  409.                         else
  410.                             ++hiscnt;
  411.                     }
  412.                     if (hiscnt < 0 || history[hiscnt] == NULL)
  413.                     {
  414.                         hiscnt = i;
  415.                         break;
  416.                     }
  417.                     if ((c != K_SUARROW && c != K_SDARROW) || hiscnt == i ||
  418.                             STRNCMP(history[hiscnt], lookfor, (size_t)j) == 0)
  419.                         break;
  420.                 }
  421.  
  422.                 if (hiscnt != i)        /* jumped to other entry */
  423.                 {
  424.                     STRCPY(buff, history[hiscnt]);
  425.                     cmdpos = cmdlen = STRLEN(buff);
  426.                     redrawcmd();
  427.                 }
  428.                 continue;
  429.  
  430.         case Ctrl('V'):
  431.                 putcmdline('^', buff);
  432.                 c = get_literal(&nextc);    /* get next (two) character(s) */
  433.                 do_abbr = FALSE;            /* don't do abbreviation now */
  434.                 break;
  435.  
  436. #ifdef DIGRAPHS
  437.         case Ctrl('K'):
  438.                 putcmdline('?', buff);
  439.                   c = vgetc();
  440.                 if (c == ESC)
  441.                     goto do_esc;
  442.                 if (charsize(c) == 1)
  443.                     putcmdline(c, buff);
  444.                 cc = vgetc();
  445.                 if (cc == ESC)
  446.                     goto do_esc;
  447.                 c = getdigraph(c, cc, TRUE);
  448.                 break;
  449. #endif /* DIGRAPHS */
  450.         }
  451.  
  452.         /* we come here if we have a normal character */
  453.  
  454.         if (do_abbr && !isidchar(c) && ccheck_abbr(c))
  455.             continue;
  456.  
  457.         if (cmdlen < CMDBUFFSIZE - 2)
  458.         {
  459.                 for (i = cmdlen++; i > cmdpos; --i)
  460.                         buff[i] = buff[i - 1];
  461.                 buff[cmdpos] = c;
  462.                 msg_outtrans(buff + cmdpos, cmdlen - cmdpos);
  463.                 ++cmdpos;
  464.                 i = charsize(c);
  465.                 cmdspos += i;
  466.         }
  467.         msg_check();
  468.     }
  469.     retval = OK;                /* when we get here we have a valid command line */
  470.  
  471. returncmd:
  472.     buff[cmdlen] = NUL;
  473.     /*
  474.      * put line in history buffer
  475.      */
  476.     if (cmdlen != 0)
  477.     {
  478.         if (hislen != 0)
  479.         {
  480.             if (++hisidx == hislen)
  481.                 hisidx = 0;
  482.             free(history[hisidx]);
  483.             history[hisidx] = strsave(buff);
  484.         }
  485.         if (firstc == ':')
  486.         {
  487.             free(new_last_cmdline);
  488.             new_last_cmdline = strsave(buff);
  489.         }
  490.     }
  491.  
  492.     /*
  493.      * If the screen was shifted up, redraw the whole screen (later).
  494.      * If the line is too long, clear it, so ruler and shown command do
  495.      * not get printed in the middle of it.
  496.      */
  497.     msg_check();
  498.     State = NORMAL;
  499.     return retval;
  500. }
  501.  
  502. /*
  503.  * put a character on the command line.
  504.  * Used for CTRL-V and CTRL-K
  505.  */
  506.     static void
  507. putcmdline(c, buff)
  508.     int        c;
  509.     char_u    *buff;
  510. {
  511.     char_u    buf[2];
  512.  
  513.     buf[0] = c;
  514.     buf[1] = 0;
  515.     msg_outtrans(buf, 1);
  516.     msg_outtrans(buff + cmdpos, cmdlen - cmdpos);
  517.     cursorcmd();
  518. }
  519.  
  520. /*
  521.  * this fuction is called when the screen size changes
  522.  */
  523.     void
  524. redrawcmdline()
  525. {
  526.     msg_scrolled = 0;
  527.     compute_cmdrow();
  528.     redrawcmd();
  529.     cursorcmd();
  530. }
  531.  
  532.     void
  533. compute_cmdrow()
  534. {
  535.     cmdline_row = lastwin->w_winpos + lastwin->w_height + lastwin->w_status_height;
  536. }
  537.  
  538. /*
  539.  * Redraw what is currently on the command line.
  540.  */
  541.     void
  542. redrawcmd()
  543. {
  544.     register int    i;
  545.  
  546.     msg_start();
  547.     msg_outchar(cmdfirstc);
  548.     msg_outtrans(cmdbuff, cmdlen);
  549.     msg_ceol();
  550.  
  551.     cmdspos = 1;
  552.     for (i = 0; i < cmdlen && i < cmdpos; ++i)
  553.         cmdspos += charsize(cmdbuff[i]);
  554. }
  555.  
  556.     static void
  557. cursorcmd()
  558. {
  559.     msg_pos(cmdline_row + (cmdspos / (int)Columns), cmdspos % (int)Columns);
  560.     windgoto(msg_row, msg_col);
  561. }
  562.  
  563. /*
  564.  * Check the word in front of the cursor for an abbreviation.
  565.  * Called when the non-id character "c" has been entered.
  566.  * When an abbreviation is recognized it is removed from the text with
  567.  * backspaces and the replacement string is inserted, followed by "c".
  568.  */
  569.     static int
  570. ccheck_abbr(c)
  571.     int c;
  572. {
  573.     if (p_paste || no_abbr)            /* no abbreviations or in paste mode */
  574.         return FALSE;
  575.     
  576.     return check_abbr(c, cmdbuff, cmdpos, 0);
  577. }
  578.  
  579. /*
  580.  * docmdline(): execute an Ex command line
  581.  *
  582.  * 1. If no line given, get one.
  583.  * 2. Split up in parts separated with '|'.
  584.  *
  585.  * This function may be called recursively!
  586.  *
  587.  * return FAIL if commandline could not be executed, OK otherwise
  588.  */
  589.     int
  590. docmdline(cmdline)
  591.     char_u        *cmdline;
  592. {
  593.     char_u        buff[CMDBUFFSIZE];        /* command line */
  594.     char_u        *nextcomm;
  595.  
  596. /*
  597.  * 1. If no line given: get one.
  598.  */
  599.     if (cmdline == NULL)
  600.     {
  601.         if (getcmdline(':', buff) == FAIL)
  602.             return FAIL;
  603.     }
  604.     else
  605.     {
  606.         if (STRLEN(cmdline) > (size_t)(CMDBUFFSIZE - 2))
  607.         {
  608.             emsg(e_toolong);
  609.             return FAIL;
  610.         }
  611.         /* Make a copy of the command so we can mess with it. */
  612.         STRCPY(buff, cmdline);
  613.     }
  614.  
  615. /*
  616.  * 2. Loop for each '|' separated command.
  617.  *    DoOneCmd will set nextcommand to NULL if there is no trailing '|'.
  618.  */
  619.     for (;;)
  620.     {
  621.         nextcomm = DoOneCmd(buff);
  622.         if (nextcomm == NULL)
  623.             break;
  624.         STRCPY(buff, nextcomm);
  625.     }
  626. /*
  627.  * If the command was typed, remember it for register :
  628.  * Do this AFTER executing the command to make :@: work.
  629.  */
  630.     if (cmdline == NULL && new_last_cmdline != NULL)
  631.     {
  632.         free(last_cmdline);
  633.         last_cmdline = new_last_cmdline;
  634.         new_last_cmdline = NULL;
  635.     }
  636.     return OK;
  637. }
  638.  
  639. /*
  640.  * Execute one Ex command.
  641.  *
  642.  * 2. skip comment lines and leading space
  643.  * 3. parse range
  644.  * 4. parse command
  645.  * 5. parse arguments
  646.  * 6. switch on command name
  647.  *
  648.  * This function may be called recursively!
  649.  */
  650.     static char_u *
  651. DoOneCmd(buff)
  652.     char_u *buff;
  653. {
  654.     char_u                cmdbuf[CMDBUFFSIZE];    /* for '%' and '#' expansion */
  655.     char_u                c;
  656.     register char_u        *p;
  657.     char_u                *q;
  658.     char_u                *cmd, *arg;
  659.     char_u                *editcmd = NULL;        /* +command arg. for doecmd() */
  660.     linenr_t             doecmdlnum = 0;            /* lnum in new file for doecmd() */
  661.     int                 i = 0;                    /* init to shut up gcc */
  662.     int                    cmdidx;
  663.     int                    argt;
  664.     register linenr_t    lnum;
  665.     long                n;
  666.     int                    addr_count;    /* number of address specifications */
  667.     FPOS                pos;
  668.     int                    append = FALSE;            /* write with append */
  669.     int                    usefilter = FALSE;        /* filter instead of file name */
  670.     char_u                *nextcomm = NULL;        /* no next command yet */
  671.     int                    amount = 0;                /* for ":>" and ":<"; init for gcc */
  672.  
  673.     if (quitmore)
  674.         --quitmore;        /* when not editing the last file :q has to be typed twice */
  675. /*
  676.  * 2. skip comment lines and leading space, colons or bars
  677.  */
  678.     for (cmd = buff; *cmd && strchr(" \t:|", *cmd) != NULL; cmd++)
  679.         ;
  680.  
  681.     if (*cmd == '"' || *cmd == NUL)    /* ignore comment and empty lines */
  682.         goto doend;
  683.  
  684. /*
  685.  * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
  686.  *
  687.  * where 'addr' is:
  688.  *
  689.  * %          (entire file)
  690.  * $  [+-NUM]
  691.  * 'x [+-NUM] (where x denotes a currently defined mark)
  692.  * .  [+-NUM]
  693.  * [+-NUM]..
  694.  * NUM
  695.  *
  696.  * The cmd pointer is updated to point to the first character following the
  697.  * range spec. If an initial address is found, but no second, the upper bound
  698.  * is equal to the lower.
  699.  */
  700.  
  701.     addr_count = 0;
  702.     --cmd;
  703.     do
  704.     {
  705.         ++cmd;                            /* skip ',' or ';' */
  706.         line1 = line2;
  707.         line2 = curwin->w_cursor.lnum;            /* default is current line number */
  708.         skipspace(&cmd);
  709.         lnum = get_address(&cmd);
  710.         if (lnum == MAXLNUM)
  711.         {
  712.             if (*cmd == '%')            /* '%' - all lines */
  713.             {
  714.                 ++cmd;
  715.                 line1 = 1;
  716.                 line2 = curbuf->b_ml.ml_line_count;
  717.                 ++addr_count;
  718.             }
  719.         }
  720.         else
  721.             line2 = lnum;
  722.         addr_count++;
  723.  
  724.         if (*cmd == ';')
  725.         {
  726.             if (line2 == 0)
  727.                 curwin->w_cursor.lnum = 1;
  728.             else
  729.                 curwin->w_cursor.lnum = line2;
  730.         }
  731.     } while (*cmd == ',' || *cmd == ';');
  732.  
  733.     /* One address given: set start and end lines */
  734.     if (addr_count == 1)
  735.     {
  736.         line1 = line2;
  737.             /* ... but only implicit: really no address given */
  738.         if (lnum == MAXLNUM)
  739.             addr_count = 0;
  740.     }
  741.  
  742. /*
  743.  * 4. parse command
  744.  */
  745.  
  746.     skipspace(&cmd);
  747.  
  748.     /*
  749.      * If we got a line, but no command, then go to the line.
  750.      * If we find a '|' or '\n' we set nextcomm.
  751.      */
  752.     if (*cmd == NUL || *cmd == '"' ||
  753.             ((*cmd == '|' || *cmd == '\n') &&
  754.                     (nextcomm = cmd + 1) != NULL))        /* just an assignment */
  755.     {
  756.         if (addr_count != 0)
  757.         {
  758.             /*
  759.              * strange vi behaviour: ":3" jumps to line 3
  760.              * ":3|..." prints line 3
  761.              */
  762.             if (*cmd == '|')
  763.             {
  764.                 cmdidx = CMD_print;
  765.                 goto cmdswitch;            /* UGLY goto */
  766.             }
  767.             if (line2 == 0)
  768.                 curwin->w_cursor.lnum = 1;
  769.             else if (line2 > curbuf->b_ml.ml_line_count)
  770.                 curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count;
  771.             else
  772.                 curwin->w_cursor.lnum = line2;
  773.             curwin->w_cursor.col = 0;
  774.             cursupdate();
  775.         }
  776.         goto doend;
  777.     }
  778.  
  779.     /*
  780.      * Isolate the command and search for it in the command table.
  781.      * Exeptions:
  782.      * - the 'k' command can directly be followed by any character.
  783.      * - the 's' command can be followed directly by 'c', 'g' or 'r'
  784.      *        but :sre[wind] is another command.
  785.      */
  786.     if (*cmd == 'k')
  787.     {
  788.         cmdidx = CMD_k;
  789.         p = cmd + 1;
  790.     }
  791.     else if (*cmd == 's' && strchr("cgr", cmd[1]) != NULL && STRNCMP("sre", cmd, (size_t)3) != 0)
  792.     {
  793.         cmdidx = CMD_substitute;
  794.         p = cmd + 1;
  795.     }
  796.     else
  797.     {
  798.         p = cmd;
  799.         while (isalpha(*p))
  800.             ++p;
  801.         if (p == cmd && strchr("@!=><&~#", *p) != NULL)    /* non-alpha command */
  802.             ++p;
  803.         i = (int)(p - cmd);
  804.  
  805.         for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
  806.             if (STRNCMP(cmdnames[cmdidx].cmd_name, (char *)cmd, (size_t)i) == 0)
  807.                 break;
  808.         if (i == 0 || cmdidx == CMD_SIZE)
  809.         {
  810.             emsg(e_invcmd);
  811.             goto doend;
  812.         }
  813.     }
  814.  
  815.     if (*p == '!')                    /* forced commands */
  816.     {
  817.         ++p;
  818.         forceit = TRUE;
  819.     }
  820.     else
  821.         forceit = FALSE;
  822.  
  823. /*
  824.  * 5. parse arguments
  825.  */
  826.     argt = cmdnames[cmdidx].cmd_argt;
  827.  
  828.     if (!(argt & RANGE) && addr_count)
  829.     {
  830.         emsg(e_norange);
  831.         goto doend;
  832.     }
  833.  
  834. /*
  835.  * If the range is backwards, ask for confirmation and, if given, swap
  836.  * line1 & line2 so it's forwards again.
  837.  * When global command is busy, don't ask, will fail below.
  838.  */
  839.     if (!global_busy && line1 > line2)
  840.     {
  841.         if (ask_yesno((char_u *)"Backwards range given, OK to swap") != 'y')
  842.             goto doend;
  843.         lnum = line1;
  844.         line1 = line2;
  845.         line2 = lnum;
  846.     }
  847.     /*
  848.      * don't complain about the range if it is not used
  849.      * (could happen if line_count is accidently set to 0)
  850.      */
  851.     if (line1 < 0 || line2 < 0  || line1 > line2 || ((argt & RANGE) &&
  852.                     !(argt & NOTADR) && line2 > curbuf->b_ml.ml_line_count))
  853.     {
  854.         emsg(e_invrange);
  855.         goto doend;
  856.     }
  857.  
  858.     if ((argt & NOTADR) && addr_count == 0)        /* default is 1, not cursor */
  859.         line2 = 1;
  860.  
  861.     if (!(argt & ZEROR))            /* zero in range not allowed */
  862.     {
  863.         if (line1 == 0)
  864.             line1 = 1;
  865.         if (line2 == 0)
  866.             line2 = 1;
  867.     }
  868.  
  869.     /*
  870.      * for the :make command we insert the 'makeprg' option here,
  871.      * so things like % get expanded
  872.      */
  873.     if (cmdidx == CMD_make)
  874.     {
  875.         if (STRLEN(p_mp) + STRLEN(p) + 2 >= (unsigned)CMDBUFFSIZE)
  876.         {
  877.             emsg(e_toolong);
  878.             goto doend;
  879.         }
  880.         STRCPY(cmdbuf, p_mp);
  881.         STRCAT(cmdbuf, " ");
  882.         STRCAT(cmdbuf, p);
  883.         STRCPY(buff,   cmdbuf);
  884.         p = buff;
  885.     }
  886.  
  887.     arg = p;                        /* remember start of argument */
  888.     skipspace(&arg);
  889.  
  890.     if ((argt & NEEDARG) && *arg == NUL)
  891.     {
  892.         emsg(e_argreq);
  893.         goto doend;
  894.     }
  895.  
  896.     if (cmdidx == CMD_write)
  897.     {
  898.         if (*arg == '>')                        /* append */
  899.         {
  900.             if (*++arg != '>')                /* typed wrong */
  901.             {
  902.                 EMSG("Use w or w>>");
  903.                 goto doend;
  904.             }
  905.             ++arg;
  906.             skipspace(&arg);
  907.             append = TRUE;
  908.         }
  909.         else if (*arg == '!')                    /* :w !filter */
  910.         {
  911.             ++arg;
  912.             usefilter = TRUE;
  913.         }
  914.     }
  915.  
  916.     if (cmdidx == CMD_read)
  917.     {
  918.         usefilter = forceit;                    /* :r! filter if forceit */
  919.         if (*arg == '!')                        /* :r !filter */
  920.         {
  921.             ++arg;
  922.             usefilter = TRUE;
  923.         }
  924.     }
  925.  
  926.     if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
  927.     {
  928.         amount = 1;
  929.         while (*arg == *cmd)        /* count number of '>' or '<' */
  930.         {
  931.             ++arg;
  932.             ++amount;
  933.         }
  934.         skipspace(&arg);
  935.     }
  936.  
  937.     /*
  938.      * Check for '|' to separate commands and '"' to start comments.
  939.      * Don't do this for ":read !cmd" and ":write !cmd".
  940.      */
  941.     if ((argt & TRLBAR) && !usefilter)
  942.     {
  943.         p = arg;
  944.         while (*p)
  945.         {
  946.             if (*p == Ctrl('V'))
  947.             {
  948.                 if ((argt & USECTRLV) && p[1] != NUL)    /* skip CTRL-V and next char */
  949.                     ++p;
  950.                 else                    /* remove CTRL-V and skip next char */
  951.                     STRCPY(p, p + 1);
  952.             }
  953.             else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|' || *p == '\n')
  954.             {
  955.                 if (*(p - 1) == '\\')    /* remove the backslash */
  956.                 {
  957.                     STRCPY(p - 1, p);
  958.                     --p;
  959.                 }
  960.                 else
  961.                 {
  962.                     if (*p == '|' || *p == '\n')
  963.                         nextcomm = p + 1;
  964.                     *p = NUL;
  965.                     break;
  966.                 }
  967.             }
  968.             ++p;
  969.         }
  970.         if (!(argt & NOTRLCOM))            /* remove trailing spaces */
  971.             del_spaces(arg);
  972.     }
  973.  
  974.     if ((argt & DFLALL) && addr_count == 0)
  975.     {
  976.         line1 = 1;
  977.         line2 = curbuf->b_ml.ml_line_count;
  978.     }
  979.  
  980.     regname = 0;
  981.         /* accept numbered register only when no count allowed (:put) */
  982.     if ((argt & REGSTR) && *arg != NUL && is_yank_buffer(*arg, FALSE) && !((argt & COUNT) && isdigit(*arg)))
  983.     {
  984.         regname = *arg;
  985.         ++arg;
  986.         skipspace(&arg);
  987.     }
  988.  
  989.     if ((argt & COUNT) && isdigit(*arg))
  990.     {
  991.         n = getdigits(&arg);
  992.         skipspace(&arg);
  993.         if (n <= 0)
  994.         {
  995.             emsg(e_zerocount);
  996.             goto doend;
  997.         }
  998.         if (argt & NOTADR)        /* e.g. :buffer 2, :sleep 3 */
  999.         {
  1000.             line2 = n;
  1001.             if (addr_count == 0)
  1002.                 addr_count = 1;
  1003.         }
  1004.         else
  1005.         {
  1006.             line1 = line2;
  1007.             line2 += n - 1;
  1008.             ++addr_count;
  1009.         }
  1010.     }
  1011.  
  1012.     if (!(argt & EXTRA) && strchr("|\"", *arg) == NULL)    /* no arguments allowed */
  1013.     {
  1014.         emsg(e_trailing);
  1015.         goto doend;
  1016.     }
  1017.  
  1018.     /*
  1019.      * change '%' to curbuf->b_filename, '#' to curwin->w_altfile
  1020.      */
  1021.     if (argt & XFILE)
  1022.     {
  1023.         for (p = arg; *p; ++p)
  1024.         {
  1025.             c = *p;
  1026.             if (c != '%' && c != '#')    /* nothing to expand */
  1027.                 continue;
  1028.             if (*(p - 1) == '\\')        /* remove escaped char */
  1029.             {
  1030.                 STRCPY(p - 1, p);
  1031.                 --p;
  1032.                 continue;
  1033.             }
  1034.  
  1035.             if (c == '%')                /* current file */
  1036.             {
  1037.                 if (check_fname() == FAIL)
  1038.                     goto doend;
  1039.                 q = curbuf->b_xfilename;
  1040.                 n = 1;                    /* length of what we expand */
  1041.             }
  1042.             else                        /* '#': alternate file */
  1043.             {
  1044.                 q = p + 1;
  1045.                 i = (int)getdigits(&q);
  1046.                 n = q - p;                /* length of what we expand */
  1047.  
  1048.                 if (buflist_name_nr(i, &q, &doecmdlnum) == FAIL)
  1049.                 {
  1050.                     emsg(e_noalt);
  1051.                     goto doend;
  1052.                 }
  1053.             }
  1054.             i = STRLEN(arg) + STRLEN(q) + 3;
  1055.             if (nextcomm)
  1056.                 i += STRLEN(nextcomm);
  1057.             if (i > CMDBUFFSIZE)
  1058.             {
  1059.                 emsg(e_toolong);
  1060.                 goto doend;
  1061.             }
  1062.             /*
  1063.              * we built the new argument in cmdbuf[], then copy it back to buff[]
  1064.              */
  1065.             *p = NUL;                            /* truncate at the '#' or '%' */
  1066.             STRCPY(cmdbuf, arg);                /* copy up to there */
  1067.             i = p - arg;                        /* remember the lenght */
  1068.             STRCAT(cmdbuf, q);                    /* append the file name */
  1069.             if (*(p + n) == '<')                /* may remove extension */
  1070.             {
  1071.                 ++n;
  1072.                 if ((arg = (char_u *)strrchr((char *)q, '.')) != NULL &&
  1073.                                 arg >= gettail(q))
  1074.                     *(cmdbuf + (arg - q) + i) = NUL;
  1075.             }
  1076.             i = STRLEN(cmdbuf);                    /* remember the end of the filename */
  1077.             STRCAT(cmdbuf, p+n);                /* append what is after '#' or '%' */
  1078.             p = buff + i - 1;                    /* remember where to continue */
  1079.             if (nextcomm)                        /* append next command */
  1080.             {
  1081.                 i = STRLEN(cmdbuf) + 1;
  1082.                 STRCPY(cmdbuf + i, nextcomm);
  1083.                 nextcomm = buff + i;
  1084.             }
  1085.             STRCPY(buff, cmdbuf);                /* copy back to buff[] */
  1086.             arg = buff;
  1087.         }
  1088.  
  1089.         /*
  1090.          * One file argument: expand wildcards.
  1091.          * Don't do this with ":r !command" or ":w !command".
  1092.          */
  1093.         if (argt & NOSPC)
  1094.         {
  1095.             if (has_wildcard(arg) && !usefilter)
  1096.             {
  1097.                 if ((p = ExpandOne(arg, TRUE, -1)) == NULL)
  1098.                     goto doend;
  1099.                 if (STRLEN(p) + arg - buff < CMDBUFFSIZE - 2)
  1100.                     STRCPY(arg, p);
  1101.                 else
  1102.                     emsg(e_toolong);
  1103.                 free(p);
  1104.             }
  1105.         }
  1106.     }
  1107.  
  1108. /*
  1109.  * 6. switch on command name
  1110.  */
  1111. cmdswitch:
  1112.     switch (cmdidx)
  1113.     {
  1114.         /*
  1115.          * quit current window, quit Vim if closed the last window
  1116.          */
  1117.         case CMD_quit:
  1118.                         /* if more files or windows we won't exit */
  1119.                 if (check_more(FALSE) == OK && firstwin == lastwin)
  1120.                     exiting = TRUE;
  1121.                 if (check_changed(curbuf, FALSE, FALSE) ||
  1122.                             check_more(TRUE) == FAIL ||
  1123.                             (firstwin == lastwin && check_changed_any(FALSE)))
  1124.                 {
  1125.                     exiting = FALSE;
  1126.                     settmode(1);
  1127.                     break;
  1128.                 }
  1129.                 if (firstwin == lastwin)    /* quit last window */
  1130.                     getout(0);
  1131.                 close_window(TRUE);            /* may free buffer */
  1132.                 break;
  1133.  
  1134.         /*
  1135.          * try to quit all windows
  1136.          */
  1137.         case CMD_qall:
  1138.                 exiting = TRUE;
  1139.                 if (!check_changed_any(FALSE))
  1140.                     getout(0);
  1141.                 exiting = FALSE;
  1142.                 settmode(1);
  1143.                 break;
  1144.  
  1145.         /*
  1146.          * close current window, unless it is the last one
  1147.          */
  1148.         case CMD_close:
  1149.                 close_window(FALSE);        /* don't free buffer */
  1150.                 break;
  1151.  
  1152.         /*
  1153.          * close all but current window, unless it is the last one
  1154.          */
  1155.         case CMD_only:
  1156.                 close_others(TRUE);
  1157.                 break;
  1158.  
  1159.         case CMD_stop:
  1160.         case CMD_suspend:
  1161.                 if (!forceit)
  1162.                     autowrite_all();
  1163.                 gotocmdend();
  1164.                 flushbuf();
  1165.                 stoptermcap();
  1166.                 mch_restore_title(3);    /* restore window titles */
  1167.                 mch_suspend();            /* call machine specific function */
  1168.                 maketitle();
  1169.                 starttermcap();
  1170.                 if (T_CVV != NULL && *T_CVV)
  1171.                 {
  1172.                     /* Scroll screen down before drawing over it */
  1173.                     outstr(T_CVV);
  1174.                     outstr(T_CV);
  1175.                 }
  1176.                 must_redraw = CLEAR;
  1177.                 break;
  1178.  
  1179.         case CMD_exit:
  1180.         case CMD_xit:
  1181.         case CMD_wq:
  1182.                             /* if more files or windows we won't exit */
  1183.                 if (check_more(FALSE) == OK && firstwin == lastwin)
  1184.                     exiting = TRUE;
  1185.                 if (((cmdidx == CMD_wq ||
  1186.                         (curbuf->b_nwindows == 1 && curbuf->b_changed)) &&
  1187.                         (check_readonly() || dowrite(arg, FALSE) == FAIL)) ||
  1188.                     check_more(TRUE) == FAIL || 
  1189.                     (firstwin == lastwin && check_changed_any(FALSE)))
  1190.                 {
  1191.                     exiting = FALSE;
  1192.                     settmode(1);
  1193.                     break;
  1194.                 }
  1195.                 if (firstwin == lastwin)    /* quit last window, exit Vim */
  1196.                     getout(0);
  1197.                 close_window(TRUE);            /* quit current window, may free buffer */
  1198.                 break;
  1199.  
  1200.         case CMD_xall:        /* write all changed files and exit */
  1201.         case CMD_wqall:        /* write all changed files and quit */
  1202.                 exiting = TRUE;
  1203.                 /* FALLTHROUGH */
  1204.  
  1205.         case CMD_wall:        /* write all changed files */
  1206.                 {
  1207.                     BUF        *buf;
  1208.                     int        error = 0;
  1209.  
  1210.                     for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1211.                     {
  1212.                         if (buf->b_changed)
  1213.                         {
  1214.                             if (buf->b_filename == NULL)
  1215.                             {
  1216.                                 emsg(e_noname);
  1217.                                 ++error;
  1218.                             }
  1219.                             else if (!forceit && buf->b_p_ro)
  1220.                             {
  1221.                                 EMSG2("\"%s\" is readonly, use ! to write anyway", buf->b_xfilename);
  1222.                                 ++error;
  1223.                             }
  1224.                             else if (buf_write_all(buf) == FAIL)
  1225.                                 ++error;
  1226.                         }
  1227.                     }
  1228.                     if (exiting)
  1229.                     {
  1230.                         if (!error)
  1231.                             getout(0);            /* exit Vim */
  1232.                         exiting = FALSE;
  1233.                         settmode(1);
  1234.                     }
  1235.                 }
  1236.                 break;
  1237.  
  1238.         case CMD_preserve:                    /* put everything in .swp file */
  1239.                 ml_preserve(curbuf, TRUE);
  1240.                 break;
  1241.  
  1242.         case CMD_args:        
  1243.                     /*
  1244.                      * ":args file": handle like :next
  1245.                      */
  1246.                 if (*arg != NUL && *arg != '|' && *arg != '\n')
  1247.                     goto do_next;
  1248.  
  1249.                 nextcomm = checknextcomm(arg);    /* check for trailing command */
  1250.                 if (arg_count == 0)            /* no file name list */
  1251.                 {
  1252.                     if (check_fname() == OK)        /* check for no file name at all */
  1253.                         smsg((char_u *)"[%s]", curbuf->b_filename);
  1254.                     break;
  1255.                 }
  1256.                 gotocmdline(TRUE, NUL);
  1257.                 for (i = 0; i < arg_count; ++i)
  1258.                 {
  1259.                     if (i == curwin->w_arg_idx)
  1260.                         msg_outchar('[');
  1261.                     msg_outstr(arg_files[i]);
  1262.                     if (i == curwin->w_arg_idx)
  1263.                         msg_outchar(']');
  1264.                     msg_outchar(' ');
  1265.                 }
  1266.                 if (msg_check())        /* if message too long */
  1267.                 {
  1268.                     msg_outchar('\n');
  1269.                     wait_return(FALSE);
  1270.                 }
  1271.                 break;
  1272.  
  1273.         case CMD_wnext:
  1274.         case CMD_wNext:
  1275.         case CMD_wprevious:
  1276.                 if (cmd[1] == 'n')
  1277.                     i = curwin->w_arg_idx + (int)line2;
  1278.                 else
  1279.                     i = curwin->w_arg_idx - (int)line2;
  1280.                 line1 = 1;
  1281.                 line2 = curbuf->b_ml.ml_line_count;
  1282.                 if (dowrite(arg, FALSE) == FAIL)
  1283.                     break;
  1284.                 goto donextfile;
  1285.  
  1286.         case CMD_next:
  1287.         case CMD_snext:
  1288. do_next:
  1289.                     /*
  1290.                      * check for changed buffer now, if this fails the
  1291.                      * argument list is not redefined.
  1292.                      */
  1293.                 if (!(p_hid || cmdidx == CMD_snext) &&
  1294.                                 check_changed(curbuf, TRUE, FALSE))
  1295.                     break;
  1296.  
  1297.                 editcmd = getargcmd(&arg);        /* get +command argument */
  1298.                 nextcomm = checknextcomm(arg);    /* check for trailing command */
  1299.                 if (*arg != NUL)                /* redefine file list */
  1300.                 {
  1301.                     if (doarglist(arg) == FAIL)
  1302.                         break;
  1303.                     i = 0;
  1304.                 }
  1305.                 else
  1306.                     i = curwin->w_arg_idx + (int)line2;
  1307.  
  1308. donextfile:        if (i < 0 || i >= arg_count)
  1309.                 {
  1310.                     if (arg_count == 1)
  1311.                         EMSG("There is only one file to edit");
  1312.                     else if (i < 0)
  1313.                         EMSG("Cannot go before first file");
  1314.                     else
  1315.                         EMSG2("No more than %ld files to edit", (char_u *)(long)arg_count);
  1316.                     break;
  1317.                 }
  1318.                 if (*cmd == 's')        /* split window first */
  1319.                 {
  1320.                     if (win_split(0L, FALSE) == FAIL)
  1321.                         break;
  1322.                 }
  1323.                 else
  1324.                 {
  1325.                     register int other = FALSE;
  1326.  
  1327.                     /*
  1328.                      * if 'hidden' set, only check for changed file when re-editing
  1329.                      * the same buffer
  1330.                      */
  1331.                     other = TRUE;
  1332.                     if (p_hid)
  1333.                         other = otherfile(fix_fname(arg_files[i]));
  1334.                     if ((!p_hid || !other) && check_changed(curbuf, TRUE, !other))
  1335.                     break;
  1336.                 }
  1337.                 curwin->w_arg_idx = i;
  1338.                 (void)doecmd(arg_files[curwin->w_arg_idx], NULL, editcmd, p_hid, (linenr_t)0);
  1339.                 break;
  1340.  
  1341.         case CMD_previous:
  1342.         case CMD_sprevious:
  1343.         case CMD_Next:
  1344.         case CMD_sNext:
  1345.                 i = curwin->w_arg_idx - (int)line2;
  1346.                 goto doargument;
  1347.  
  1348.         case CMD_rewind:
  1349.         case CMD_srewind:
  1350.                 i = 0;
  1351.                 goto doargument;
  1352.  
  1353.         case CMD_last:
  1354.         case CMD_slast:
  1355.                 i = arg_count - 1;
  1356.                 goto doargument;
  1357.  
  1358.         case CMD_argument:
  1359.         case CMD_sargument:
  1360.                 if (addr_count)
  1361.                     i = line2 - 1;
  1362.                 else
  1363.                     i = curwin->w_arg_idx;
  1364. doargument:
  1365.                 editcmd = getargcmd(&arg);        /* get +command argument */
  1366.                 nextcomm = checknextcomm(arg);    /* check for trailing command */
  1367.                 goto donextfile;
  1368.  
  1369.         case CMD_all:
  1370.         case CMD_sall:
  1371.                 do_arg_all();        /* open a window for each argument */
  1372.                 break;
  1373.  
  1374.         case CMD_buffer:            /* :[N]buffer [N]     to buffer N */
  1375.         case CMD_sbuffer:            /* :[N]sbuffer [N]     to buffer N */
  1376.                 if (addr_count == 0)        /* default is current buffer */
  1377.                     (void)do_buffer(*cmd == 's', 0, FORWARD, 0, 0);
  1378.                 else
  1379.                     (void)do_buffer(*cmd == 's', 1, FORWARD, (int)line2, 0);
  1380.                 break;
  1381.  
  1382.         case CMD_bmodified:            /* :[N]bmod    [N]         to next modified buffer */
  1383.         case CMD_sbmodified:        /* :[N]sbmod [N]      to next modified buffer */
  1384.                 (void)do_buffer(*cmd == 's', 3, FORWARD, (int)line2, 0);
  1385.                 break;
  1386.  
  1387.         case CMD_bnext:                /* :[N]bnext [N]     to next buffer */
  1388.         case CMD_sbnext:            /* :[N]sbnext [N]      to next buffer */
  1389.                 (void)do_buffer(*cmd == 's', 0, FORWARD, (int)line2, 0);
  1390.                 break;
  1391.  
  1392.         case CMD_bNext:                /* :[N]bNext [N]     to previous buffer */
  1393.         case CMD_bprevious:            /* :[N]bprevious [N] to previous buffer */
  1394.         case CMD_sbNext:            /* :[N]sbNext [N]      to previous buffer */
  1395.         case CMD_sbprevious:        /* :[N]sbprevious [N] to previous buffer */
  1396.                 (void)do_buffer(*cmd == 's', 0, BACKWARD, (int)line2, 0);
  1397.                 break;
  1398.  
  1399.         case CMD_brewind:            /* :brewind             to first buffer */
  1400.         case CMD_sbrewind:            /* :sbrewind         to first buffer */
  1401.                 (void)do_buffer(*cmd == 's', 1, FORWARD, 0, 0);
  1402.                 break;
  1403.  
  1404.         case CMD_blast:                /* :blast             to last buffer */
  1405.         case CMD_sblast:            /* :sblast             to last buffer */
  1406.                 (void)do_buffer(*cmd == 's', 2, FORWARD, 0, 0);
  1407.                 break;
  1408.  
  1409.         case CMD_bunload:            /* :[N]bunload[!] [N] unload buffer */
  1410.                 i = 2;
  1411.         case CMD_bdelete:            /* :[N]bdelete[!] [N] delete buffer */
  1412.                 if (cmdidx == CMD_bdelete)
  1413.                     i = 3;
  1414.                 /*
  1415.                  * addr_count == 0: ":bdel" - delete current buffer
  1416.                  * addr_count == 1: ":N bdel" or ":bdel N [N ..] - first delete
  1417.                  *                    buffer 'line2', then any other arguments.
  1418.                  * addr_count == 2: ":N,N bdel" - delete buffers in range
  1419.                  */
  1420.                 if (addr_count == 0)
  1421.                     (void)do_buffer(i, 0, FORWARD, 0, forceit);
  1422.                 else
  1423.                 {
  1424.                     int do_current = FALSE;        /* delete current buffer? */
  1425.  
  1426.                     if (addr_count == 2)
  1427.                         n = line1;
  1428.                     else
  1429.                         n = line2;
  1430.                     for ( ;!got_int; breakcheck())
  1431.                     {
  1432.                         /*
  1433.                          * delete the current buffer last, otherwise when the
  1434.                          * current buffer is deleted, the next buffer becomes
  1435.                          * the current one and will be loaded, which may then
  1436.                          * also be deleted, etc.
  1437.                          */
  1438.                         if (n == curbuf->b_fnum)
  1439.                             do_current = TRUE;
  1440.                         else
  1441.                             (void)do_buffer(i, 1, FORWARD, (int)n, forceit);
  1442.                         if (addr_count == 2)
  1443.                         {
  1444.                             if (++n > line2)
  1445.                                 break;
  1446.                         }
  1447.                         else
  1448.                         {
  1449.                             skipspace(&arg);
  1450.                             if (*arg == NUL)
  1451.                                 break;
  1452.                             if (!isdigit(*arg))
  1453.                             {
  1454.                                 emsg(e_trailing);
  1455.                                 break;
  1456.                             }
  1457.                             n = getdigits(&arg);
  1458.                         }
  1459.                     }
  1460.                     if (!got_int && do_current)
  1461.                         (void)do_buffer(i, 1, FORWARD, (int)curbuf->b_fnum, forceit);
  1462.                 }
  1463.                 break;
  1464.  
  1465.         case CMD_unhide:
  1466.         case CMD_sunhide:
  1467.                 (void)do_buffer_all(FALSE);    /* open a window for loaded buffers */
  1468.                 break;
  1469.  
  1470.         case CMD_ball:
  1471.         case CMD_sball:
  1472.                 (void)do_buffer_all(TRUE);    /* open a window for every buffer */
  1473.                 break;
  1474.  
  1475.         case CMD_buffers:
  1476.         case CMD_files:
  1477.                 buflist_list();
  1478.                 break;
  1479.  
  1480.         case CMD_write:
  1481.                 if (usefilter)        /* input lines to shell command */
  1482.                     dofilter(line1, line2, arg, TRUE, FALSE);
  1483.                 else
  1484.                     (void)dowrite(arg, append);
  1485.                 break;
  1486.  
  1487.             /*
  1488.              * set screen mode
  1489.              * if no argument given, just get the screen size and redraw
  1490.              */
  1491.         case CMD_mode:
  1492.                 if (*arg == NUL || mch_screenmode(arg) != FAIL)
  1493.                     set_winsize(0, 0, FALSE);
  1494.                 break;
  1495.  
  1496.                 /*
  1497.                  * set, increment or decrement current window height
  1498.                  */
  1499.         case CMD_resize:
  1500.                 n = atol((char *)arg);
  1501.                 if (*arg == '-' || *arg == '+')
  1502.                     win_setheight(curwin->w_height + (int)n);
  1503.                 else
  1504.                 {
  1505.                     if (n == 0)        /* default is very high */
  1506.                         n = 9999;
  1507.                     win_setheight((int)n);
  1508.                 }
  1509.                 break;
  1510.  
  1511.                 /*
  1512.                  * :split [[+command] file]  split window with current or new file
  1513.                  * :new [[+command] file]    split window with no or new file
  1514.                  */
  1515.         case CMD_split:
  1516.         case CMD_new:
  1517.                 if (win_split(addr_count ? line2 : 0L, FALSE) == FAIL)
  1518.                     break;
  1519.                 /*FALLTHROUGH*/
  1520.  
  1521.         case CMD_edit:
  1522.         case CMD_ex:
  1523.         case CMD_visual:
  1524.                 editcmd = getargcmd(&arg);        /* get +command argument */
  1525.                 nextcomm = checknextcomm(arg);    /* check for trailing command */
  1526.                 if ((cmdidx == CMD_new) && *arg == NUL)
  1527.                     (void)doecmd(NULL, NULL, editcmd, TRUE, (linenr_t)1);
  1528.                 else if (cmdidx != CMD_split || *arg != NUL)
  1529.                     (void)doecmd(arg, NULL, editcmd, p_hid, doecmdlnum);
  1530.                 else
  1531.                     updateScreen(NOT_VALID);
  1532.                 break;
  1533.  
  1534.         case CMD_file:
  1535.                 if (*arg != NUL)
  1536.                 {
  1537.                     if (setfname(arg, NULL, TRUE) == FAIL)
  1538.                         break;
  1539.                     curbuf->b_notedited = TRUE;
  1540.                     maketitle();
  1541.                 }
  1542.                 fileinfo(did_cd);        /* print full filename if :cd used */
  1543.                 break;
  1544.  
  1545.         case CMD_swapname:
  1546.                 p = curbuf->b_ml.ml_mfp->mf_fname;
  1547.                 if (p == NULL)
  1548.                     MSG("No swap file");
  1549.                 else
  1550.                     msg(p);
  1551.                 break;
  1552.  
  1553.         case CMD_mfstat:        /* print memfile statistics, for debugging */
  1554.                 mf_statistics();
  1555.                 break;
  1556.  
  1557.         case CMD_read:
  1558.                 if (usefilter)
  1559.                 {
  1560.                     dofilter(line1, line2, arg, FALSE, TRUE);            /* :r!cmd */
  1561.                     break;
  1562.                 }
  1563.                 if (!u_save(line2, (linenr_t)(line2 + 1)))
  1564.                     break;
  1565.                 if (*arg == NUL)
  1566.                 {
  1567.                     if (check_fname() == FAIL)    /* check for no file name at all */
  1568.                         break;
  1569.                     i = readfile(curbuf->b_filename, curbuf->b_sfilename, line2, FALSE, (linenr_t)0, MAXLNUM);
  1570.                 }
  1571.                 else
  1572.                     i = readfile(arg, NULL, line2, FALSE, (linenr_t)0, MAXLNUM);
  1573.                 if (i == FAIL)
  1574.                 {
  1575.                     emsg2(e_notopen, arg);
  1576.                     break;
  1577.                 }
  1578.                 updateScreen(NOT_VALID);
  1579.                 break;
  1580.  
  1581.         case CMD_cd:
  1582.         case CMD_chdir:
  1583. #ifdef UNIX
  1584.                 /*
  1585.                  * for UNIX ":cd" means: go to home directory
  1586.                  */
  1587.                 if (*arg == NUL)     /* use cmdbuf for home directory name */
  1588.                 {
  1589.                     expand_env("$HOME", cmdbuf, CMDBUFFSIZE);
  1590.                     arg = cmdbuf;
  1591.                 }
  1592. #endif
  1593.                 if (*arg != NUL)
  1594.                 {
  1595.                     if (!did_cd)
  1596.                     {
  1597.                         BUF        *buf;
  1598.  
  1599.                             /* use full path from now on for names of files
  1600.                              * being edited and swap files */
  1601.                         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  1602.                         {
  1603.                             buf->b_xfilename = buf->b_filename;
  1604.                             mf_fullname(buf->b_ml.ml_mfp);
  1605.                         }
  1606.                         status_redraw_all();
  1607.                     }
  1608.                     did_cd = TRUE;
  1609.                     if (chdir((char *)arg))
  1610.                         emsg(e_failed);
  1611.                     break;
  1612.                 }
  1613.                 /*FALLTHROUGH*/
  1614.  
  1615.         case CMD_pwd:
  1616.                 if (vim_dirname(NameBuff, MAXPATHL) == OK)
  1617.                     msg(NameBuff);
  1618.                 else
  1619.                     emsg(e_unknown);
  1620.                 break;
  1621.  
  1622.         case CMD_equal:
  1623.                 smsg((char_u *)"line %ld", (long)line2);
  1624.                 break;
  1625.  
  1626.         case CMD_list:
  1627.                 i = curwin->w_p_list;
  1628.                 curwin->w_p_list = 1;
  1629.         case CMD_number:                /* :nu */
  1630.         case CMD_pound:                    /* :# */
  1631.         case CMD_print:                    /* :p */
  1632.                 gotocmdline(TRUE, NUL);
  1633.                 cursor_off();
  1634.                 for ( ;!got_int; breakcheck())
  1635.                 {
  1636.                     if (curwin->w_p_nu || cmdidx == CMD_number || cmdidx == CMD_pound)
  1637.                     {
  1638.                         sprintf((char *)IObuff, "%7ld ", (long)line1);
  1639.                         msg_outstr(IObuff);
  1640.                     }
  1641.                     msg_prt_line(ml_get(line1));
  1642.                     if (++line1 > line2)
  1643.                         break;
  1644.                     msg_outchar('\n');
  1645.                     flushbuf();            /* show one line at a time */
  1646.                 }
  1647.  
  1648.                 if (cmdidx == CMD_list)
  1649.                     curwin->w_p_list = i;
  1650.  
  1651.                     /*
  1652.                      * if we have one line that runs into the shown command,
  1653.                      * or more than one line, call wait_return()
  1654.                      * also do this when global_busy, so we remember to call
  1655.                      * wait_return at the end of the global command.
  1656.                      */
  1657.                 if (msg_check() || global_busy)
  1658.                 {
  1659.                     msg_outchar('\n');
  1660.                     wait_return(FALSE);
  1661.                 }
  1662.                 break;
  1663.  
  1664.         case CMD_shell:
  1665.                 doshell(NULL);
  1666.                 break;
  1667.  
  1668.         case CMD_sleep:
  1669.                 sleep((int)line2);
  1670.                 break;
  1671.  
  1672.         case CMD_tag:
  1673.                 dotag(arg, 0, addr_count ? (int)line2 : 1);
  1674.                 break;
  1675.  
  1676.         case CMD_pop:
  1677.                 dotag((char_u *)"", 1, addr_count ? (int)line2 : 1);
  1678.                 break;
  1679.  
  1680.         case CMD_tags:
  1681.                 dotags();
  1682.                 break;
  1683.  
  1684.         case CMD_marks:
  1685.                 domarks();
  1686.                 break;
  1687.  
  1688.         case CMD_jumps:
  1689.                 dojumps();
  1690.                 break;
  1691.  
  1692.         case CMD_digraphs:
  1693. #ifdef DIGRAPHS
  1694.                 if (*arg)
  1695.                     putdigraph(arg);
  1696.                 else
  1697.                     listdigraphs();
  1698. #else
  1699.                 EMSG("No digraphs in this version");
  1700. #endif /* DIGRAPHS */
  1701.                 break;
  1702.  
  1703.         case CMD_set:
  1704.                 (void)doset(arg);
  1705.                 break;
  1706.  
  1707.         case CMD_abbreviate:
  1708.         case CMD_cabbrev:
  1709.         case CMD_iabbrev:
  1710.         case CMD_cnoreabbrev:
  1711.         case CMD_inoreabbrev:
  1712.         case CMD_noreabbrev:
  1713.         case CMD_unabbreviate:
  1714.         case CMD_cunabbrev:
  1715.         case CMD_iunabbrev:
  1716.                 i = ABBREV;
  1717.                 goto doabbr;        /* almost the same as mapping */
  1718.  
  1719.         case CMD_cmap:
  1720.         case CMD_imap:
  1721.         case CMD_map:
  1722.         case CMD_cnoremap:
  1723.         case CMD_inoremap:
  1724.         case CMD_noremap:
  1725.                 /*
  1726.                  * If we are sourcing .exrc or .vimrc in current directory we
  1727.                  * print the mappings for security reasons.
  1728.                  */
  1729.                 if (secure)
  1730.                 {
  1731.                     secure = 2;
  1732.                     msg_outtrans(cmd, -1);
  1733.                     msg_outchar('\n');
  1734.                 }
  1735.         case CMD_cunmap:
  1736.         case CMD_iunmap:
  1737.         case CMD_unmap:
  1738.                 i = 0;
  1739. doabbr:
  1740.                 if (*cmd == 'c')        /* cmap, cunmap, cnoremap, etc. */
  1741.                 {
  1742.                     i += CMDLINE;
  1743.                     ++cmd;
  1744.                 }
  1745.                 else if (*cmd == 'i')    /* imap, iunmap, inoremap, etc. */
  1746.                 {
  1747.                     i += INSERT;
  1748.                     ++cmd;
  1749.                 }
  1750.                 else if (forceit || i)    /* map!, unmap!, noremap!, abbrev */
  1751.                     i += INSERT + CMDLINE;
  1752.                 else
  1753.                     i += NORMAL;            /* map, unmap, noremap */
  1754.                 switch (domap((*cmd == 'n') ? 2 : (*cmd == 'u'), arg, i))
  1755.                 {
  1756.                     case 1: emsg(e_invarg);
  1757.                             break;
  1758.                     case 2: emsg(e_nomap);
  1759.                             break;
  1760.                     case 3: emsg(e_ambmap);
  1761.                             break;
  1762.                 }
  1763.                 break;
  1764.  
  1765.         case CMD_display:
  1766.                 dodis();        /* display buffer contents */
  1767.                 break;
  1768.  
  1769.         case CMD_help:
  1770.                 help();
  1771.                 break;
  1772.  
  1773.         case CMD_version:
  1774.                 msg(longVersion);
  1775.                 break;
  1776.  
  1777.         case CMD_winsize:                    /* obsolete command */
  1778.                 line1 = getdigits(&arg);
  1779.                 skipspace(&arg);
  1780.                 line2 = getdigits(&arg);
  1781.                 set_winsize((int)line1, (int)line2, TRUE);
  1782.                 break;
  1783.  
  1784.         case CMD_delete:
  1785.         case CMD_yank:
  1786.         case CMD_rshift:
  1787.         case CMD_lshift:
  1788.                 yankbuffer = regname;
  1789.                 curbuf->b_startop.lnum = line1;
  1790.                 curbuf->b_endop.lnum = line2;
  1791.                 nlines = line2 - line1 + 1;
  1792.                 mtype = MLINE;
  1793.                 curwin->w_cursor.lnum = line1;
  1794.                 switch (cmdidx)
  1795.                 {
  1796.                 case CMD_delete:
  1797.                     dodelete();
  1798.                     break;
  1799.                 case CMD_yank:
  1800.                     (void)doyank(FALSE);
  1801.                     curwin->w_cursor.lnum = line2;        /* put cursor on last line */
  1802.                     break;
  1803.                 case CMD_rshift:
  1804.                     doshift(RSHIFT, FALSE, amount);
  1805.                     break;
  1806.                 case CMD_lshift:
  1807.                     doshift(LSHIFT, FALSE, amount);
  1808.                     break;
  1809.                 }
  1810.                 break;
  1811.  
  1812.         case CMD_put:
  1813.                 yankbuffer = regname;
  1814.                 curwin->w_cursor.lnum = line2;
  1815.                 doput(forceit ? BACKWARD : FORWARD, -1L, FALSE);
  1816.                 break;
  1817.  
  1818.         case CMD_t:
  1819.         case CMD_copy:
  1820.         case CMD_move:
  1821.                 n = get_address(&arg);
  1822.                 /*
  1823.                  * move or copy lines from 'line1'-'line2' to below line 'n'
  1824.                  */
  1825.                 if (n == MAXLNUM || n < 0 || n > curbuf->b_ml.ml_line_count)
  1826.                 {
  1827.                     emsg(e_invaddr);
  1828.                     break;
  1829.                 }
  1830.  
  1831.                 if (cmdidx == CMD_move)
  1832.                 {
  1833.                     if (do_move(line1, line2, n) == FAIL)
  1834.                         break;
  1835.                 }
  1836.                 else
  1837.                     do_copy(line1, line2, n);
  1838.                 u_clearline();
  1839.                 curwin->w_cursor.col = 0;
  1840.                 updateScreen(NOT_VALID);
  1841.                 break;
  1842.  
  1843.         case CMD_and:            /* :& */
  1844.         case CMD_tilde:            /* :~ */
  1845.         case CMD_substitute:    /* :s */
  1846.                 dosub(line1, line2, arg, &nextcomm,
  1847.                             cmdidx == CMD_substitute ? 0 :
  1848.                             cmdidx == CMD_and ? 1 : 2);
  1849.                 break;
  1850.  
  1851.         case CMD_join:
  1852.                 curwin->w_cursor.lnum = line1;
  1853.                 if (line1 == line2)
  1854.                 {
  1855.                     if (addr_count >= 2)    /* :2,2join does nothing */
  1856.                         break;
  1857.                     if (line2 == curbuf->b_ml.ml_line_count)
  1858.                     {
  1859.                         beep();
  1860.                         break;
  1861.                     }
  1862.                     ++line2;
  1863.                 }
  1864.                 dodojoin(line2 - line1 + 1, !forceit, TRUE);
  1865.                 break;
  1866.  
  1867.         case CMD_global:
  1868.                 if (forceit)
  1869.                     *cmd = 'v';
  1870.         case CMD_vglobal:
  1871.                 doglob(*cmd, line1, line2, arg);
  1872.                 break;
  1873.  
  1874.         case CMD_at:                /* :[addr]@r */
  1875.                 curwin->w_cursor.lnum = line2;
  1876.                 if (doexecbuf(*arg) == FAIL)            /* put the register in mapbuf */
  1877.                     beep();
  1878.                 else
  1879.                     (void)docmdline((char_u *)NULL);    /* execute from the mapbuf */
  1880.                 break;
  1881.  
  1882.         case CMD_bang:
  1883.                 dobang(addr_count, line1, line2, forceit, arg);
  1884.                 break;
  1885.  
  1886.         case CMD_undo:
  1887.                 u_undo(1);
  1888.                 break;
  1889.  
  1890.         case CMD_redo:
  1891.                 u_redo(1);
  1892.                 break;
  1893.  
  1894.         case CMD_source:
  1895.                 if (forceit)    /* :so! read vi commands */
  1896.                     (void)openscript(arg);
  1897.                 else
  1898.                 {
  1899.                     ++no_wait_return;
  1900.                     if (dosource(arg) == FAIL)        /* :so read ex commands */
  1901.                         emsg2(e_notopen, arg);
  1902.                     --no_wait_return;
  1903.                     if (need_wait_return)
  1904.                         wait_return(FALSE);
  1905.                 }
  1906.                 break;
  1907.  
  1908.         case CMD_mkvimrc:
  1909.                 if (*arg == NUL)
  1910.                     arg = (char_u *)VIMRC_FILE;
  1911.                 /*FALLTHROUGH*/
  1912.  
  1913.         case CMD_mkexrc:
  1914.                 {
  1915.                     FILE    *fd;
  1916.  
  1917.                     if (*arg == NUL)
  1918.                         arg = (char_u *)EXRC_FILE;
  1919. #ifdef UNIX
  1920.                         /* with Unix it is possible to open a directory */
  1921.                     if (isdir(arg) == TRUE)
  1922.                     {
  1923.                         EMSG2("\"%s\" is a directory", arg);
  1924.                         break;
  1925.                     }
  1926. #endif
  1927.                     if (!forceit && (fd = fopen((char *)arg, "r")) != NULL)
  1928.                     {
  1929.                         fclose(fd);
  1930.                         EMSG2("\"%s\" exists (use ! to override)", arg);
  1931.                         break;
  1932.                     }
  1933.  
  1934.                     if ((fd = fopen((char *)arg, "w")) == NULL)
  1935.                     {
  1936.                         EMSG2("Cannot open \"%s\" for writing", arg);
  1937.                         break;
  1938.                     }
  1939.                     if (makemap(fd) == FAIL || makeset(fd) == FAIL || fclose(fd))
  1940.                         emsg(e_write);
  1941.                     break;
  1942.                 }
  1943.  
  1944.         case CMD_cc:
  1945.                     qf_jump(0, atoi((char *)arg));
  1946.                     break;
  1947.  
  1948.         case CMD_cf:
  1949.                     if (*arg != NUL)
  1950.                     {
  1951.                         /*
  1952.                          * Great trick: Insert 'ef=' before arg.
  1953.                          * Always ok, because "cf " must be there.
  1954.                          */
  1955.                         arg -= 3;
  1956.                         arg[0] = 'e';
  1957.                         arg[1] = 'f';
  1958.                         arg[2] = '=';
  1959.                         (void)doset(arg);
  1960.                     }
  1961.                     (void)qf_init();
  1962.                     break;
  1963.  
  1964.         case CMD_cl:
  1965.                     qf_list();
  1966.                     break;
  1967.  
  1968.         case CMD_cn:
  1969.                     qf_jump(FORWARD, *arg == NUL ? 1 : atoi((char *)arg));
  1970.                     break;
  1971.  
  1972.         case CMD_cp:
  1973.                     qf_jump(BACKWARD, *arg == NUL ? 1 : atoi((char *)arg));
  1974.                     break;
  1975.  
  1976.         case CMD_cq:
  1977.                     getout(1);        /* this does not always work. why? */
  1978.  
  1979.         case CMD_mark:
  1980.         case CMD_k:
  1981.                     pos = curwin->w_cursor;            /* save curwin->w_cursor */
  1982.                     curwin->w_cursor.lnum = line2;
  1983.                     curwin->w_cursor.col = 0;
  1984.                     (void)setmark(*arg);            /* set mark */
  1985.                     curwin->w_cursor = pos;            /* restore curwin->w_cursor */
  1986.                     break;
  1987.  
  1988. #ifdef SETKEYMAP
  1989.         case CMD_setkeymap:
  1990.                     set_keymap(arg);
  1991.                     break;
  1992. #endif
  1993.  
  1994.         case CMD_center:
  1995.         case CMD_right:
  1996.         case CMD_left:
  1997.                     do_align(line1, line2, atoi((char *)arg),
  1998.                             cmdidx == CMD_center ? 0 : cmdidx == CMD_right ? 1 : -1);
  1999.                     break;
  2000.  
  2001.         case CMD_make:
  2002.                     domake(arg);
  2003.                     break;
  2004.  
  2005.         default:
  2006.                     emsg(e_invcmd);
  2007.     }
  2008.  
  2009.  
  2010. doend:
  2011.     forceit = FALSE;        /* reset now so it can be used in getfile() */
  2012.     if (nextcomm && *nextcomm == NUL)        /* not really a next command */
  2013.         nextcomm = NULL;
  2014.     return nextcomm;
  2015. }
  2016.  
  2017. /*
  2018.  * if 'autowrite' option set, try to write the file
  2019.  *
  2020.  * return FAIL for failure, OK otherwise
  2021.  */
  2022.     int
  2023. autowrite(buf)
  2024.     BUF        *buf;
  2025. {
  2026.     if (!p_aw || (!forceit && buf->b_p_ro) || buf->b_filename == NULL)
  2027.         return FAIL;
  2028.     return buf_write_all(buf);
  2029. }
  2030.  
  2031. /*
  2032.  * flush all buffers, except the ones that are readonly
  2033.  */
  2034.     void
  2035. autowrite_all()
  2036. {
  2037.     BUF        *buf;
  2038.  
  2039.     if (!p_aw)
  2040.         return;
  2041.     for (buf = firstbuf; buf; buf = buf->b_next)
  2042.         if (buf->b_changed && !buf->b_p_ro)
  2043.             (void)buf_write_all(buf);
  2044. }
  2045.  
  2046. /*
  2047.  * flush the contents of a buffer, unless it has no file name
  2048.  *
  2049.  * return FAIL for failure, OK otherwise
  2050.  */
  2051.     static int
  2052. buf_write_all(buf)
  2053.     BUF        *buf;
  2054. {
  2055.     return (buf_write(buf, buf->b_filename, buf->b_sfilename, (linenr_t)1, buf->b_ml.ml_line_count, 0, 0, TRUE));
  2056. }
  2057.  
  2058. /*
  2059.  * write current buffer to file 'fname'
  2060.  * if 'append' is TRUE, append to the file
  2061.  *
  2062.  * if *fname == NUL write to current file
  2063.  * if b_notedited is TRUE, check for overwriting current file
  2064.  *
  2065.  * return FAIL for failure, OK otherwise
  2066.  */
  2067.     static int
  2068. dowrite(fname, append)
  2069.     char_u    *fname;
  2070.     int        append;
  2071. {
  2072.     FILE    *fd;
  2073.     int        other;
  2074.     char_u    *sfname = NULL;                /* init to shut up gcc */
  2075.  
  2076.     if (*fname == NUL)
  2077.         other = FALSE;
  2078.     else
  2079.     {
  2080.         sfname = fname;
  2081.         fname = fix_fname(fname);
  2082.         other = otherfile(fname);
  2083.     }
  2084.  
  2085.     /*
  2086.      * if we have a new file name put it in the list of alternate file names
  2087.      */
  2088.     if (other)
  2089.         setaltfname(fname, sfname, (linenr_t)1);
  2090.  
  2091.     /*
  2092.      * writing to the current file is not allowed in readonly mode
  2093.      * and need a file name
  2094.      */
  2095.     if (!other && (check_readonly() || check_fname() == FAIL))
  2096.         return FAIL;
  2097.  
  2098.     if (!other)
  2099.     {
  2100.         fname = curbuf->b_filename;
  2101.         sfname = curbuf->b_sfilename;
  2102.     }
  2103.  
  2104.     /*
  2105.      * write to other file or b_notedited set: overwriting only allowed with '!'
  2106.      */
  2107.     if ((other || curbuf->b_notedited) && !forceit && !append && !p_wa && (fd = fopen((char *)fname, "r")) != NULL)
  2108.     {                                /* don't overwrite existing file */
  2109.         fclose(fd);
  2110. #ifdef UNIX
  2111.             /* with UNIX it is possible to open a directory */
  2112.         if (isdir(fname) == TRUE)
  2113.             EMSG2("\"%s\" is a directory", fname);
  2114.         else
  2115. #endif
  2116.             emsg(e_exists);
  2117.         return FAIL;
  2118.     }
  2119.     return (buf_write(curbuf, fname, sfname, line1, line2, append, forceit, TRUE));
  2120. }
  2121.  
  2122. /*
  2123.  * start editing a new file
  2124.  *
  2125.  *    fname: the file name
  2126.  *                - full path if sfname used,
  2127.  *                - any file name if sfname is NULL
  2128.  *                - empty string to re-edit with the same file name (but may be
  2129.  *                    in a different directory)
  2130.  *                - NULL to start an empty buffer
  2131.  *   sfname: the short file name (or NULL)
  2132.  *  command: the command to be executed after loading the file
  2133.  *     hide: if TRUE don't free the current buffer
  2134.  *  newlnum: put cursor on this line number (if possible)
  2135.  *
  2136.  * return FAIL for failure, OK otherwise
  2137.  */
  2138.     int
  2139. doecmd(fname, sfname, command, hide, newlnum)
  2140.     char_u        *fname;
  2141.     char_u        *sfname;
  2142.     char_u        *command;
  2143.     int            hide;
  2144.     linenr_t    newlnum;
  2145. {
  2146.     int            other_file;                /* TRUE if editing another file */
  2147.     int            oldbuf = FALSE;            /* TRUE if using existing buffer */
  2148.     BUF            *buf;
  2149.  
  2150.         /* if no short name given, use fname for short name */
  2151.     if (sfname == NULL)
  2152.         sfname = fname;
  2153.  
  2154.     if (fname == NULL)
  2155.         other_file = TRUE;
  2156.     else if (*fname == NUL && curbuf->b_filename == NULL)    /* there is no file name */
  2157.         other_file = FALSE;
  2158.     else
  2159.     {
  2160.         if (*fname == NUL)                /* re-edit with same file name */
  2161.         {
  2162.             fname = curbuf->b_filename;
  2163.             sfname = curbuf->b_sfilename;
  2164.         }
  2165.         fname = fix_fname(fname);        /* may expand to full path name */
  2166.         other_file = otherfile(fname);
  2167.     }
  2168. /*
  2169.  * if the file was changed we may not be allowed to abandon it
  2170.  * - if we are going to re-edit the same file
  2171.  * - or if we are the only window on this file and if hide is FALSE
  2172.  */
  2173.     if ((!other_file || (curbuf->b_nwindows == 1 && !hide)) &&
  2174.                         check_changed(curbuf, FALSE, !other_file))
  2175.     {
  2176.         if (other_file && fname != NULL)
  2177.             setaltfname(fname, sfname, (linenr_t)1);
  2178.         return FAIL;
  2179.     }
  2180. /*
  2181.  * If we are starting to edit another file, open a (new) buffer.
  2182.  * Otherwise we re-use the current buffer.
  2183.  */
  2184.     if (other_file)
  2185.     {
  2186.         curwin->w_alt_fnum = curbuf->b_fnum;
  2187.         buflist_altlnum();
  2188.  
  2189.         buf = buflist_new(fname, sfname, 1L, TRUE);
  2190.         if (buf == NULL)
  2191.             return FAIL;
  2192.         if (buf->b_ml.ml_mfp == NULL)        /* no memfile yet */
  2193.         {
  2194.             oldbuf = FALSE;
  2195.             buf->b_nwindows = 1;
  2196.         }
  2197.         else                                /* existing memfile */
  2198.         {
  2199.             oldbuf = TRUE;
  2200.             ++buf->b_nwindows;
  2201.         }
  2202.         /*
  2203.          * make the (new) buffer the one used by the current window
  2204.          * if the old buffer becomes unused, free it if hide is FALSE
  2205.          * If the current buffer was empty and has no file name, curbuf
  2206.          * is returned by buflist_new().
  2207.          */
  2208.         if (buf != curbuf)
  2209.         {
  2210.             close_buffer(curbuf, !hide, FALSE);
  2211.             curwin->w_buffer = buf;
  2212.             curbuf = buf;
  2213.         }
  2214.  
  2215.         curwin->w_pcmark.lnum = 1;
  2216.         curwin->w_pcmark.col = 0;
  2217.     }
  2218.     else if (check_fname() == FAIL)
  2219.         return FAIL;
  2220.  
  2221. /*
  2222.  * If we get here we are sure to start editing
  2223.  */
  2224.         /* don't redraw until the cursor is in the right line */
  2225.     ++RedrawingDisabled;
  2226.  
  2227. /*
  2228.  * other_file    oldbuf
  2229.  *    FALSE        FALSE        re-edit same file, buffer is re-used
  2230.  *    FALSE        TRUE        not posible
  2231.  *  TRUE        FALSE        start editing new file, new buffer
  2232.  *  TRUE        TRUE        start editing in existing buffer (nothing to do)
  2233.  */
  2234.     if (!other_file)                    /* re-use the buffer */
  2235.     {
  2236.         if (newlnum == 0)
  2237.             newlnum = curwin->w_cursor.lnum;
  2238.         buf_freeall(curbuf);            /* free all things for buffer */
  2239.         buf_clear(curbuf);
  2240.         curbuf->b_startop.lnum = 0;        /* clear '[ and '] marks */
  2241.         curbuf->b_endop.lnum = 0;
  2242.     }
  2243.  
  2244.     if (!oldbuf)                        /* need to read the file */
  2245.         (void)open_buffer();
  2246.     win_init(curwin);
  2247.     maketitle();
  2248.  
  2249.     if (newlnum && command == NULL)
  2250.     {
  2251.         curwin->w_cursor.lnum = newlnum;
  2252.         curwin->w_cursor.col = 0;
  2253.     }
  2254.     check_cursor();
  2255.  
  2256.     /*
  2257.      * Did not read the file, need to show some info about the file.
  2258.      * Do this after setting the cursor.
  2259.      */
  2260.     if (oldbuf)
  2261.         fileinfo(did_cd);
  2262.  
  2263.     if (command != NULL)
  2264.         docmdline(command);
  2265.     --RedrawingDisabled;
  2266.     if (!skip_redraw)
  2267.         updateScreen(CURSUPD);            /* redraw now */
  2268.  
  2269.     if (p_im)
  2270.         stuffReadbuff((char_u *)"i");    /* start editing in insert mode */
  2271.     return OK;
  2272. }
  2273.  
  2274. /*
  2275.  * get + command from ex argument
  2276.  */
  2277.     static char_u *
  2278. getargcmd(argp)
  2279.     char_u **argp;
  2280. {
  2281.     char_u *arg = *argp;
  2282.     char_u *command = NULL;
  2283.  
  2284.     if (*arg == '+')        /* +[command] */
  2285.     {
  2286.         ++arg;
  2287.         if (isspace(*arg))
  2288.             command = (char_u *)"$";
  2289.         else
  2290.         {
  2291.             command = arg;
  2292.             /*
  2293.              * should check for "\ " (but vi has a bug that prevents it to work)
  2294.              */
  2295.             skiptospace(&arg);
  2296.         }
  2297.         if (*arg)
  2298.             *arg++ = NUL;    /* terminate command with NUL */
  2299.         
  2300.         skipspace(&arg);    /* skip over spaces */
  2301.         *argp = arg;
  2302.     }
  2303.     return command;
  2304. }
  2305.  
  2306. /*
  2307.  * look for command separator '|' or '\n'
  2308.  */
  2309.     static char_u *
  2310. checknextcomm(arg)
  2311.     char_u *arg;
  2312. {
  2313.     char_u *p;
  2314.     char_u *nextcomm = NULL;
  2315.  
  2316.     for (p = arg; *p; ++p)
  2317.     {
  2318.         if (*p == '\\' && p[1])
  2319.             ++p;
  2320.         else if (*p == '|' || *p == '\n')
  2321.         {
  2322.             nextcomm = p + 1;    /* remember start of next command */
  2323.             *p = NUL;            /* delete '|' or '\n' */
  2324.             del_spaces(arg);    /* delete spaces in front of '|' or '\n' */
  2325.             break;
  2326.         }
  2327.     }
  2328.     return nextcomm;
  2329. }
  2330.  
  2331.     static void
  2332. domake(arg)
  2333.     char_u *arg;
  2334. {
  2335.     if (*p_ef == NUL)
  2336.     {
  2337.         EMSG("errorfile option not set");
  2338.         return;
  2339.     }
  2340.     if (curbuf->b_changed)
  2341.         (void)autowrite(curbuf);
  2342.     remove((char *)p_ef);
  2343.     outchar(':');
  2344.     outstr(arg);        /* show what we are doing */
  2345.     sprintf((char *)IObuff, "%s %s %s", arg, p_sp, p_ef);
  2346.     doshell(IObuff);
  2347. #ifdef AMIGA
  2348.     flushbuf();
  2349.     vpeekc();        /* read window status report and redraw before message */
  2350. #endif
  2351.     (void)qf_init();
  2352.     remove((char *)p_ef);
  2353. }
  2354.  
  2355. /* 
  2356.  * Redefine the argument list to 'str'.
  2357.  *
  2358.  * Return FAIL for failure, OK otherwise.
  2359.  */
  2360.     static int
  2361. doarglist(str)
  2362.     char_u *str;
  2363. {
  2364.     int        new_count = 0;
  2365.     char_u    **new_files = NULL;
  2366.     int        exp_count;
  2367.     char_u    **exp_files;
  2368.     char_u    **t;
  2369.     char_u    *p;
  2370.     int        inquote;
  2371.     int        i;
  2372.  
  2373.     while (*str)
  2374.     {
  2375.         /*
  2376.          * create a new entry in new_files[]
  2377.          */
  2378.         t = (char_u **)lalloc((long_u)(sizeof(char_u *) * (new_count + 1)), TRUE);
  2379.         if (t != NULL)
  2380.             for (i = new_count; --i >= 0; )
  2381.                 t[i] = new_files[i];
  2382.         free(new_files);
  2383.         if (t == NULL)
  2384.             return FAIL;
  2385.         new_files = t;
  2386.         new_files[new_count++] = str;
  2387.  
  2388.         /*
  2389.          * isolate one argument, taking quotes
  2390.          */
  2391.         inquote = FALSE;
  2392.         for (p = str; *str; ++str)
  2393.         {
  2394.             /*
  2395.              * for MSDOS a backslash is part of a file name.
  2396.              * Only skip ", space and tab.
  2397.              */
  2398. #ifdef MSDOS
  2399.             if (*str == '\\' && (str[1] == '"' || str[1] == ' ' || str[1] == '\t'))
  2400. #else
  2401.             if (*str == '\\' && str[1] != NUL)
  2402. #endif
  2403.                 *p++ = *++str;
  2404.             else
  2405.             {
  2406.                 if (!inquote && isspace(*str))
  2407.                     break;
  2408.                 if (*str == '"')
  2409.                     inquote ^= TRUE;
  2410.                 else
  2411.                     *p++ = *str;
  2412.             }
  2413.         }
  2414.         skipspace(&str);
  2415.         *p = NUL;
  2416.     }
  2417.     
  2418.     i = ExpandWildCards(new_count, new_files, &exp_count, &exp_files, FALSE, TRUE);
  2419.     free(new_files);
  2420.     if (i == FAIL)
  2421.         return FAIL;
  2422.     if (exp_count == 0)
  2423.     {
  2424.         emsg(e_nomatch);
  2425.         return FAIL;
  2426.     }
  2427.     if (arg_exp)                /* arg_files[] has been allocated, free it */
  2428.         FreeWild(arg_count, arg_files);
  2429.     else
  2430.         arg_exp = TRUE;
  2431.     arg_files = exp_files;
  2432.     arg_count = exp_count;
  2433.  
  2434.     /*
  2435.      * put all file names in the buffer list
  2436.      */
  2437.     for (i = 0; i < arg_count; ++i)
  2438.         (void)buflist_add(arg_files[i]);
  2439.  
  2440.     return OK;
  2441. }
  2442.  
  2443.     void
  2444. gotocmdline(clr, firstc)
  2445.     int                clr;
  2446.     int                firstc;
  2447. {
  2448.     msg_start();
  2449.     if (clr)            /* clear the bottom line(s) */
  2450.         msg_ceol();        /* will reset clear_cmdline */
  2451.     windgoto(cmdline_row, 0);
  2452.     if (firstc)
  2453.         msg_outchar(firstc);
  2454. }
  2455.  
  2456.     void
  2457. gotocmdend()
  2458. {
  2459.     windgoto((int)Rows - 1, 0);
  2460.     outchar('\n');
  2461. }
  2462.  
  2463.     static int
  2464. check_readonly()
  2465. {
  2466.     if (!forceit && curbuf->b_p_ro)
  2467.     {
  2468.         emsg(e_readonly);
  2469.         return TRUE;
  2470.     }
  2471.     return FALSE;
  2472. }
  2473.  
  2474. /*
  2475.  * return TRUE if buffer was changed and cannot be abandoned.
  2476.  */
  2477.     static int
  2478. check_changed(buf, checkaw, mult_win)
  2479.     BUF        *buf;
  2480.     int        checkaw;        /* do autowrite if buffer was changed */
  2481.     int        mult_win;        /* check also when several windows for this buffer */
  2482. {
  2483.     if (    !forceit &&
  2484.             buf->b_changed && (mult_win || buf->b_nwindows <= 1) &&
  2485.             (!checkaw || autowrite(buf) == FAIL))
  2486.     {
  2487.         emsg(e_nowrtmsg);
  2488.         return TRUE;
  2489.     }
  2490.     return FALSE;
  2491. }
  2492.  
  2493. /*
  2494.  * return TRUE if any buffer was changed and cannot be abandoned.
  2495.  */
  2496.     static int
  2497. check_changed_any(checkaw)
  2498.     int        checkaw;        /* do autowrite if buffer was changed */
  2499. {
  2500.     BUF        *buf;
  2501.  
  2502.     if (!forceit)
  2503.     {
  2504.         for (buf = firstbuf; buf != NULL; buf = buf->b_next)
  2505.         {
  2506.             if (buf->b_changed && (!checkaw || autowrite(buf) == FAIL))
  2507.             {
  2508.                 EMSG2("No write since last change for buffer \"%s\"",
  2509.                         buf->b_xfilename == NULL ? (char_u *)"No File" : buf->b_xfilename);
  2510.                 return TRUE;
  2511.             }
  2512.         }
  2513.     }
  2514.     return FALSE;
  2515. }
  2516.  
  2517. /*
  2518.  * return FAIL if there is no filename, OK if there is one
  2519.  * give error message for FAIL
  2520.  */
  2521.     int
  2522. check_fname()
  2523. {
  2524.     if (curbuf->b_filename == NULL)
  2525.     {
  2526.         emsg(e_noname);
  2527.         return FAIL;
  2528.     }
  2529.     return OK;
  2530. }
  2531.  
  2532. /*
  2533.  * - if there are more files to edit
  2534.  * - and this is the last window
  2535.  * - and forceit not used
  2536.  * - and not repeated twice on a row
  2537.  *      return FAIL and give error message if 'message' TRUE
  2538.  * return OK otherwise
  2539.  */
  2540.     static int
  2541. check_more(message)
  2542.     int message;            /* when FALSE check only, no messages */
  2543. {
  2544.     if (!forceit && firstwin == lastwin && curwin->w_arg_idx + 1 < arg_count &&
  2545.                                     quitmore == 0)
  2546.     {
  2547.         if (message)
  2548.         {
  2549.             emsg2((char_u *)"%ld more files to edit", (char_u *)(long)(arg_count - curwin->w_arg_idx - 1));
  2550.             quitmore = 2;            /* next try to quit is allowed */
  2551.         }
  2552.         return FAIL;
  2553.     }
  2554.     return OK;
  2555. }
  2556.  
  2557. /*
  2558.  * try to abandon current file and edit "fname"
  2559.  * return 1 for "normal" error, 2 for "not written" error, 0 for success
  2560.  * -1 for succesfully opening another file
  2561.  * 'lnum' is the line number for the cursor in the new file (if non-zero).
  2562.  */
  2563.     int
  2564. getfile(fname, sfname, setpm, lnum)
  2565.     char_u        *fname;
  2566.     char_u        *sfname;
  2567.     int            setpm;
  2568.     linenr_t    lnum;
  2569. {
  2570.     int other;
  2571.  
  2572.     fname_expand(&fname, &sfname);    /* make fname full path and set sfname */
  2573.     other = otherfile(fname);
  2574.  
  2575.     if (other && !forceit && curbuf->b_nwindows == 1 &&
  2576.             !p_hid && curbuf->b_changed && autowrite(curbuf) == FAIL)
  2577.     {
  2578.         emsg(e_nowrtmsg);
  2579.         return 2;        /* file has been changed */
  2580.     }
  2581.     if (setpm)
  2582.         setpcmark();
  2583.     if (!other)
  2584.     {
  2585.         if (lnum != 0)
  2586.             curwin->w_cursor.lnum = lnum;
  2587.         check_cursor();
  2588.         curwin->w_cursor.col = 0;
  2589.  
  2590.         return 0;        /* it's in the same file */
  2591.     }
  2592.     if (doecmd(fname, sfname, NULL, p_hid, lnum) == OK)
  2593.         return -1;        /* opened another file */
  2594.     return 1;            /* error encountered */
  2595. }
  2596.  
  2597. #ifdef WEBB_COMPLETE
  2598. /*
  2599.  * vim_strncpy()
  2600.  *
  2601.  * This is here because strncpy() does not guarantee successful results when
  2602.  * the to and from strings overlap.  It is only currently called from nextwild()
  2603.  * which copies part of the command line to another part of the command line.
  2604.  * This produced garbage when expanding files etc in the middle of the command
  2605.  * line (on my terminal, anyway) -- webb.
  2606.  */
  2607.     static void
  2608. vim_strncpy(to, from, len)
  2609.     char_u *to;
  2610.     char_u *from;
  2611.     int len;
  2612. {
  2613.     int i;
  2614.  
  2615.     if (to <= from)
  2616.     {
  2617.         while (len-- && *from)
  2618.             *to++ = *from++;
  2619.         if (len >= 0)
  2620.             *to = *from;    /* Copy NUL */
  2621.     }
  2622.     else
  2623.     {
  2624.         for (i = 0; i < len; i++)
  2625.         {
  2626.             to++;
  2627.             if (*from++ == NUL)
  2628.             {
  2629.                 i++;
  2630.                 break;
  2631.             }
  2632.         }
  2633.         for (; i > 0; i--)
  2634.             *--to = *--from;
  2635.     }
  2636. }
  2637.  
  2638. /* Return FALSE if this is not an appropriate context in which to do
  2639.  * completion of anything, & TRUE if it is (even if there are no matches).  For
  2640.  * the caller, this means that the character is just passed through like a
  2641.  * normal character (instead of being expanded).  This allows :s/^I^D etc.
  2642.  */
  2643.     static int
  2644. #else
  2645.     static void
  2646. #endif /* WEBB_COMPLETE */
  2647. nextwild(buff, type)
  2648.     char_u *buff;
  2649.     int        type;
  2650. {
  2651.     int        i;
  2652.     char_u    *p1;
  2653.     char_u    *p2 = NULL;
  2654.     int        oldlen;
  2655.     int        difflen;
  2656.  
  2657. #ifdef WEBB_COMPLETE
  2658.     if (cmd_numfiles == -1)
  2659.         set_expand_context(cmdfirstc, cmdbuff);
  2660.     if (expand_context == EXPAND_UNSUCCESSFUL)
  2661.     {
  2662.         beep();
  2663.         return OK;    /* Something illegal on command line */
  2664.     }
  2665.     if (expand_context == EXPAND_NOTHING)
  2666.     {
  2667.         /* Caller can use the character as a normal char instead */
  2668.         return FAIL;
  2669.     }
  2670.     expand_interactively = TRUE;
  2671.  
  2672. #endif /* WEBB_COMPLETE */
  2673.     msg_outstr((char_u *)"...");        /* show that we are busy */
  2674.     flushbuf();
  2675.  
  2676. #ifdef WEBB_COMPLETE
  2677.     i = expand_pattern - buff;
  2678. #else
  2679.     for (i = cmdpos; i > 0 && buff[i - 1] != ' '; --i)
  2680.         ;
  2681. #endif /* WEBB_COMPLETE */
  2682.     oldlen = cmdpos - i;
  2683.  
  2684.         /* add a "*" to the file name and expand it */
  2685.     if ((p1 = addstar(&buff[i], oldlen)) != NULL)
  2686.     {
  2687.         if ((p2 = ExpandOne(p1, FALSE, type)) != NULL)
  2688.         {
  2689.             if (cmdlen + (difflen = STRLEN(p2) - oldlen) > CMDBUFFSIZE - 4)
  2690.                 emsg(e_toolong);
  2691.             else
  2692.             {
  2693. #ifdef WEBB_COMPLETE
  2694.                 vim_strncpy(&buff[cmdpos + difflen], &buff[cmdpos], cmdlen - cmdpos);
  2695. #else
  2696.                 STRNCPY(&buff[cmdpos + difflen], &buff[cmdpos], (size_t)(cmdlen - cmdpos));
  2697. #endif /* WEBB_COMPLETE */
  2698.                 STRNCPY(&buff[i], p2, STRLEN(p2));
  2699.                 cmdlen += difflen;
  2700.                 cmdpos += difflen;
  2701.             }
  2702.             free(p2);
  2703.         }
  2704.         free(p1);
  2705.     }
  2706.     redrawcmd();
  2707. #ifdef WEBB_COMPLETE
  2708.     if (cmd_numfiles <= 0 && p2 == NULL)
  2709.         beep();
  2710.     else if (cmd_numfiles == 1)
  2711.     {
  2712.         (void)ExpandOne(NULL, FALSE, -2);    /* free expanded "file" names */
  2713.         cmd_numfiles = -1;
  2714.     }
  2715.     expand_interactively = FALSE;
  2716.     return OK;
  2717. #endif /* WEBB_COMPLETE */
  2718. }
  2719.  
  2720. /*
  2721.  * Do wildcard expansion on the string 'str'.
  2722.  * Return a pointer to alloced memory containing the new string.
  2723.  * Return NULL for failure.
  2724.  *
  2725.  * mode = -2: only release file names
  2726.  * mode = -1: normal expansion, do not keep file names
  2727.  * mode =  0: normal expansion, keep file names
  2728.  * mode =  1: use next match in multiple match
  2729.  * mode =  2: use previous match in multiple match
  2730.  * mode =  3: use next match in multiple match and wrap to first
  2731.  * mode =  4: return all matches concatenated
  2732.  * mode =  5: return longest matched part
  2733.  */
  2734.     char_u *
  2735. ExpandOne(str, list_notfound, mode)
  2736.     char_u    *str;
  2737.     int        list_notfound;
  2738.     int        mode;
  2739. {
  2740.     char_u        *ss = NULL;
  2741.     static char_u **cmd_files = NULL;      /* list of input files */
  2742.     static int    findex;
  2743.     int            i, found = 0;
  2744.     int            multmatch = FALSE;
  2745.     long_u        len;
  2746.     char_u        *filesuf, *setsuf, *nextsetsuf;
  2747.     int            filesuflen, setsuflen;
  2748.  
  2749. /*
  2750.  * first handle the case of using an old match
  2751.  */
  2752.     if (mode >= 1 && mode < 4)
  2753.     {
  2754.         if (cmd_numfiles > 0)
  2755.         {
  2756.             if (mode == 2)
  2757.                 --findex;
  2758.             else    /* mode == 1 || mode == 3 */
  2759.                 ++findex;
  2760.             if (findex < 0)
  2761.                 findex = 0;
  2762.             if (findex > cmd_numfiles - 1)
  2763.             {
  2764.                 if (mode == 3)
  2765.                     findex = 0;
  2766.                 else
  2767.                     findex = cmd_numfiles - 1;
  2768.             }
  2769.             return strsave(cmd_files[findex]);
  2770.         }
  2771.         else
  2772.             return NULL;
  2773.     }
  2774.  
  2775. /* free old names */
  2776.     if (cmd_numfiles != -1 && mode < 4)
  2777.     {
  2778.         FreeWild(cmd_numfiles, cmd_files);
  2779.         cmd_numfiles = -1;
  2780.     }
  2781.     findex = 0;
  2782.  
  2783.     if (mode == -2)        /* only release file name */
  2784.         return NULL;
  2785.  
  2786.     if (cmd_numfiles == -1)
  2787.     {
  2788. #ifdef WEBB_COMPLETE
  2789.         if (ExpandFromContext((char_u *)str, &cmd_numfiles, &cmd_files, FALSE,
  2790.                                                         list_notfound) == FAIL)
  2791.             /* error: do nothing */;
  2792.         else if (cmd_numfiles == 0)
  2793.         {
  2794.             if (!expand_interactively)
  2795.                 emsg(e_nomatch);
  2796.         }
  2797. #else
  2798.         if (ExpandWildCards(1, (char_u **)&str, &cmd_numfiles, &cmd_files, FALSE, list_notfound) == FAIL)
  2799.             /* error: do nothing */;
  2800.         else if (cmd_numfiles == 0)
  2801.             emsg(e_nomatch);
  2802. #endif /* WEBB_COMPLETE */
  2803.         else if (mode < 4)
  2804.         {
  2805.             if (cmd_numfiles > 1)        /* more than one match; check suffixes */
  2806.             {
  2807.                 found = -2;
  2808.                 for (i = 0; i < cmd_numfiles; ++i)
  2809.                 {
  2810.                     if ((filesuf = STRRCHR(cmd_files[i], '.')) != NULL)
  2811.                     {
  2812.                         filesuflen = STRLEN(filesuf);
  2813.                         for (setsuf = p_su; *setsuf; setsuf = nextsetsuf)
  2814.                         {
  2815.                             if ((nextsetsuf = STRCHR(setsuf + 1, '.')) == NULL)
  2816.                                 nextsetsuf = setsuf + STRLEN(setsuf);
  2817.                             setsuflen = (int)(nextsetsuf - setsuf);
  2818.                             if (filesuflen == setsuflen &&
  2819.                                         STRNCMP(setsuf, filesuf, (size_t)setsuflen) == 0)
  2820.                                 break;
  2821.                         }
  2822.                         if (*setsuf)                /* suffix matched: ignore file */
  2823.                             continue;
  2824.                     }
  2825.                     if (found >= 0)
  2826.                     {
  2827.                         multmatch = TRUE;
  2828.                         break;
  2829.                     }
  2830.                     found = i;
  2831.                 }
  2832.             }
  2833.             if (multmatch || found < 0)
  2834.             {
  2835. #ifdef WEBB_COMPLETE
  2836.                 /* Can we ever get here unless it's while expanding
  2837.                  * interactively?  If not, we can get rid of this all together.
  2838.                  * Don't really want to wait for this message (and possibly
  2839.                  * have to hit return to continue!).
  2840.                  */
  2841.                 if (!expand_interactively)
  2842. #endif /* WEBB_COMPLETE */
  2843.                     emsg(e_toomany);
  2844. #ifdef WEBB_COMPLETE
  2845.                 else
  2846.                     beep();
  2847. #endif /* WEBB_COMPLETE */
  2848.                 found = 0;                /* return first one */
  2849.                 multmatch = TRUE;        /* for found < 0 */
  2850.             }
  2851.             if (found >= 0 && !(multmatch && mode == -1))
  2852.                 ss = strsave(cmd_files[found]);
  2853.         }
  2854.     }
  2855.  
  2856.     if (mode == 5 && cmd_numfiles > 0)        /* find longest common part */
  2857.     {
  2858.         for (len = 0; cmd_files[0][len]; ++len)
  2859.         {
  2860.             for (i = 0; i < cmd_numfiles; ++i)
  2861.             {
  2862. #ifdef AMIGA
  2863.                 if (toupper(cmd_files[i][len]) != toupper(cmd_files[0][len]))
  2864. #else
  2865.                 if (cmd_files[i][len] != cmd_files[0][len])
  2866. #endif
  2867.                     break;
  2868.             }
  2869.             if (i < cmd_numfiles)
  2870.                 break;
  2871.         }
  2872.         ss = alloc((unsigned)len + 1);
  2873.         if (ss)
  2874.         {
  2875.             STRNCPY(ss, cmd_files[0], (size_t)len);
  2876.             ss[len] = NUL;
  2877.         }
  2878.         multmatch = TRUE;                    /* don't free the names */
  2879.         findex = -1;                        /* next p_wc gets first one */
  2880.     }
  2881.  
  2882.     if (mode == 4 && cmd_numfiles > 0)        /* concatenate all file names */
  2883.     {
  2884.         len = 0;
  2885.         for (i = 0; i < cmd_numfiles; ++i)
  2886.             len += STRLEN(cmd_files[i]) + 1;
  2887.         ss = lalloc(len, TRUE);
  2888.         if (ss)
  2889.         {
  2890.             *ss = NUL;
  2891.             for (i = 0; i < cmd_numfiles; ++i)
  2892.             {
  2893.                 STRCAT(ss, cmd_files[i]);
  2894.                 if (i != cmd_numfiles - 1)
  2895.                     STRCAT(ss, " ");
  2896.             }
  2897.         }
  2898.     }
  2899.  
  2900. #ifdef WEBB_COMPLETE
  2901.     if (mode == -1 || mode == 4)
  2902. #else
  2903.     if (!multmatch || mode == -1 || mode == 4)
  2904. #endif /* WEBB_COMPLETE */
  2905.     {
  2906.         FreeWild(cmd_numfiles, cmd_files);
  2907.         cmd_numfiles = -1;
  2908.     }
  2909.     return ss;
  2910. }
  2911.  
  2912. /*
  2913.  * show all filenames that match the string "file" with length "len"
  2914.  */
  2915. #ifdef WEBB_COMPLETE
  2916.     static int
  2917. showmatches(buff)
  2918.     char_u *buff;
  2919. #else
  2920.     static void
  2921. showmatches(file, len)
  2922.     char_u *file;
  2923.     int    len;
  2924. #endif /* WEBB_COMPLETE */
  2925. {
  2926.     char_u *file_str;
  2927.     int num_files;
  2928.     char_u **files_found;
  2929.     int i, j, k;
  2930.     int maxlen;
  2931.     int lines;
  2932.     int columns;
  2933.  
  2934. #ifdef WEBB_COMPLETE
  2935.     set_expand_context(cmdfirstc, cmdbuff);
  2936.     if (expand_context == EXPAND_UNSUCCESSFUL)
  2937.     {
  2938.         beep();
  2939.         return OK;    /* Something illegal on command line */
  2940.     }
  2941.     if (expand_context == EXPAND_NOTHING)
  2942.     {
  2943.         /* Caller can use the character as a normal char instead */
  2944.         return FAIL;
  2945.     }
  2946.     expand_interactively = TRUE;
  2947.  
  2948.     /* add star to file name, or convert to regexp if not expanding files! */
  2949.     file_str = addstar(expand_pattern, (int)(buff + cmdpos - expand_pattern));
  2950.     if (file_str == NULL)
  2951.     {
  2952.         expand_interactively = FALSE;
  2953.         return OK;
  2954.     }
  2955. #else
  2956.     file_str = addstar(file, len);        /* add star to file name */
  2957.     if (file_str == NULL)
  2958.         return;
  2959. #endif /* WEBB_COMPLETE */
  2960.  
  2961.     msg_outchar('\n');
  2962.     flushbuf();
  2963.  
  2964.     /* find all files that match the description */
  2965. #ifdef WEBB_COMPLETE
  2966.     if (ExpandFromContext(file_str, &num_files, &files_found, FALSE, FALSE) == FAIL)
  2967.     {
  2968.         num_files = 0;
  2969.         files_found = (char_u **)"";
  2970.     }
  2971. #else
  2972.     if (ExpandWildCards(1, &file_str, &num_files, &files_found, FALSE, FALSE) == FAIL)
  2973.         return;
  2974. #endif /* WEBB_COMPLETE */
  2975.  
  2976.     /* find the maximum length of the file names */
  2977.     maxlen = 0;
  2978.     for (i = 0; i < num_files; ++i)
  2979.     {
  2980.         j = STRLEN(files_found[i]);
  2981.         if (j > maxlen)
  2982.             maxlen = j;
  2983.     }
  2984.  
  2985.     /* compute the number of columns and lines for the listing */
  2986.     maxlen += 2;    /* two spaces between file names */
  2987.     columns = ((int)Columns + 2) / maxlen;
  2988.     if (columns < 1)
  2989.         columns = 1;
  2990.     lines = (num_files + columns - 1) / columns;
  2991.  
  2992.     (void)set_highlight('d');    /* find out highlight mode for directories */
  2993.  
  2994.     /* list the files line by line */
  2995.     for (i = 0; i < lines; ++i)
  2996.     {
  2997.         for (k = i; k < num_files; k += lines)
  2998.         {
  2999.             if (k > i)
  3000.                 for (j = maxlen - STRLEN(files_found[k - lines]); --j >= 0; )
  3001.                     msg_outchar(' ');
  3002. #ifdef WEBB_COMPLETE
  3003.             if (expand_context == EXPAND_FILES)
  3004.                 j = isdir(files_found[k]);    /* highlight directories */
  3005.             else
  3006.                 j = FALSE;
  3007. #else
  3008.             j = isdir(files_found[k]);    /* highlight directories */
  3009. #endif /* WEBB_COMPLETE */
  3010.             if (j)
  3011.             {
  3012.                 start_highlight();
  3013.                 screen_start();        /* don't output spaces to position cursor */
  3014.             }
  3015.             msg_outstr(files_found[k]);
  3016.             if (j)
  3017.                 stop_highlight();
  3018.         }
  3019.         msg_outchar('\n');
  3020.         flushbuf();                    /* show one line at a time */
  3021.     }
  3022.     free(file_str);
  3023.     FreeWild(num_files, files_found);
  3024.  
  3025. /*
  3026.  * we redraw the command below the lines that we have just listed
  3027.  * This is a bit tricky, but it saves a lot of screen updating.
  3028.  */
  3029.     cmdline_row = msg_row;        /* will put it back later */
  3030. #ifdef WEBB_COMPLETE
  3031.  
  3032.     expand_interactively = FALSE;
  3033.     return OK;
  3034. #endif /* WEBB_COMPLETE */
  3035. }
  3036.  
  3037. /*
  3038.  * copy the file name into allocated memory and add a '*' at the end
  3039.  */
  3040.     static char_u *
  3041. addstar(fname, len)
  3042.     char_u    *fname;
  3043.     int        len;
  3044. {
  3045.     char_u    *retval;
  3046. #ifdef WEBB_COMPLETE
  3047.     int        i, j;
  3048.     int        new_len;
  3049.     char_u    save_char;
  3050.  
  3051.     if (expand_interactively && expand_context != EXPAND_FILES &&
  3052.         expand_context != EXPAND_DIRECTORIES)
  3053.     {
  3054.         /* Matching will be done internally (on something other than files).
  3055.          * So we convert the file-matching-type wildcards into our kind for
  3056.          * use with regcomp().  First work out how long it will be:
  3057.          */
  3058.         new_len = len + 2;                /* +2 for '^' at start, NUL at end */
  3059.         for (i = 0; i < len; i++)
  3060.             if (fname[i] == '*')
  3061.                 new_len++;                /* '*' needs to be replaced by '.*' */
  3062.         retval = alloc(new_len);
  3063.         if (retval != NULL)
  3064.         {
  3065.             retval[0] = '^';
  3066.             for (i = 0, j = 1; i < len; i++, j++)
  3067.                 if (fname[i] == '*')
  3068.                 {
  3069.                     retval[j++] = '.';
  3070.                     retval[j] = '*';
  3071.                 }
  3072.                 else if (fname[i] == '?')
  3073.                     retval[j] = '.';
  3074.                 else
  3075.                     retval[j] = fname[i];
  3076.             retval[j] = NUL;
  3077.         }
  3078.     }
  3079.     else
  3080.     {
  3081.         retval = alloc(len + 4);
  3082.         if (retval != NULL)
  3083.         {
  3084.             STRNCPY(retval, fname, (size_t)len);
  3085.             /*
  3086.              * Don't add a star to ~ or ~user
  3087.              */
  3088.             save_char = fname[j = len];
  3089.             fname[j] = NUL;
  3090.             if (gettail(fname)[0] != '~')
  3091.             {
  3092. #ifdef MSDOS
  3093.             /*
  3094.              * if there is no dot in the file name, add "*.*" instead of "*".
  3095.              */
  3096.                 for (i = len - 1; i >= 0; --i)
  3097.                     if (strchr(".\\/:", retval[i]))
  3098.                         break;
  3099.                 if (i < 0 || retval[i] != '.')
  3100.                 {
  3101.                     retval[len++] = '*';
  3102.                     retval[len++] = '.';
  3103.                 }
  3104. #endif
  3105.                 retval[len++] = '*';
  3106.             }
  3107.             retval[len] = NUL;
  3108.             fname[j] = save_char;
  3109.         }
  3110.     }
  3111. #else /* WEBB_COMPLETE */
  3112. #ifdef MSDOS
  3113.     int        i;
  3114. #endif
  3115.  
  3116.     retval = alloc(len + 4);
  3117.     if (retval != NULL)
  3118.     {
  3119.         STRNCPY(retval, fname, (size_t)len);
  3120. #ifdef MSDOS
  3121.     /*
  3122.      * if there is no dot in the file name, add "*.*" instead of "*".
  3123.      */
  3124.         for (i = len - 1; i >= 0; --i)
  3125.             if (strchr(".\\/:", retval[i]))
  3126.                 break;
  3127.         if (i < 0 || retval[i] != '.')
  3128.         {
  3129.             retval[len++] = '*';
  3130.             retval[len++] = '.';
  3131.         }
  3132. #endif
  3133.         retval[len] = '*';
  3134.         retval[len + 1] = 0;
  3135.     }
  3136. #endif /* WEBB_COMPLETE */
  3137.     return retval;
  3138. }
  3139.  
  3140. /*
  3141.  * dosource: read the file "fname" and execute its lines as EX commands
  3142.  *
  3143.  * This function may be called recursively!
  3144.  *
  3145.  * return FAIL if file could not be opened, OK otherwise
  3146.  */
  3147.     int
  3148. dosource(fname)
  3149.     register char_u *fname;
  3150. {
  3151.     register FILE    *fp;
  3152.     register int    len;
  3153. #ifdef MSDOS
  3154.     int                error = FALSE;
  3155. #endif
  3156.  
  3157.     expand_env(fname, NameBuff, MAXPATHL);        /* use NameBuff for expanded name */
  3158.     if ((fp = fopen((char *)NameBuff, READBIN)) == NULL)
  3159.         return FAIL;
  3160.  
  3161.     ++dont_sleep;            /* don't call sleep() in emsg() */
  3162.     len = 0;
  3163.     while (fgets((char *)IObuff + len, IOSIZE - len, fp) != NULL && !got_int)
  3164.     {
  3165.         len = STRLEN(IObuff) - 1;
  3166.         if (len >= 0 && IObuff[len] == '\n')    /* remove trailing newline */
  3167.         {
  3168. #ifdef MSDOS
  3169.             if (len > 0 && IObuff[len - 1] == '\r') /* trailing CR-LF */
  3170.                 --len;
  3171.             else
  3172.             {
  3173.                 if (!error)
  3174.                     EMSG("Warning: Wrong line separator, ^M may be missing");
  3175.                 error = TRUE;        /* lines like ":map xx yy^M" will fail */
  3176.             }
  3177. #endif
  3178.                 /* escaped newline, read more */
  3179.             if (len > 0 && len < IOSIZE && IObuff[len - 1] == Ctrl('V'))
  3180.             {
  3181.                 IObuff[len - 1] = '\n';        /* remove CTRL-V */
  3182.                 continue;
  3183.             }
  3184.             IObuff[len] = NUL;
  3185.         }
  3186.         breakcheck();        /* check for ^C here, so recursive :so will be broken */
  3187.         docmdline(IObuff);
  3188.         len = 0;
  3189.     }
  3190.     fclose(fp);
  3191.     if (got_int)
  3192.         emsg(e_interr);
  3193.     --dont_sleep;
  3194.     return OK;
  3195. }
  3196.  
  3197. /*
  3198.  * get single EX address
  3199.  */
  3200.     static linenr_t
  3201. get_address(ptr)
  3202.     char_u        **ptr;
  3203. {
  3204.     linenr_t    cursor_lnum = curwin->w_cursor.lnum;
  3205.     int            c;
  3206.     int            i;
  3207.     long        n;
  3208.     char_u      *cmd;
  3209.     FPOS        pos;
  3210.     FPOS        *fp;
  3211.     linenr_t    lnum;
  3212.  
  3213.     cmd = *ptr;
  3214.     skipspace(&cmd);
  3215.     lnum = MAXLNUM;
  3216.     do
  3217.     {
  3218.         switch (*cmd)
  3219.         {
  3220.             case '.':                         /* '.' - Cursor position */
  3221.                         ++cmd;
  3222.                         lnum = cursor_lnum;
  3223.                         break;
  3224.  
  3225.             case '$':                         /* '$' - last line */
  3226.                         ++cmd;
  3227.                         lnum = curbuf->b_ml.ml_line_count;
  3228.                         break;
  3229.  
  3230.             case '\'':                         /* ''' - mark */
  3231.                         if (*++cmd == NUL || (fp = getmark(*cmd++, FALSE)) == NULL)
  3232.                         {
  3233.                             emsg(e_umark);
  3234.                             goto error;
  3235.                         }
  3236.                         lnum = fp->lnum;
  3237.                         break;
  3238.  
  3239.             case '/':
  3240.             case '?':                        /* '/' or '?' - search */
  3241.                         c = *cmd++;
  3242.                         pos = curwin->w_cursor;        /* save curwin->w_cursor */
  3243.                         curwin->w_cursor.col = -1;    /* searchit() will increment the col */
  3244.                         if (c == '/')
  3245.                         {
  3246.                              if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)    /* :/pat on last line */
  3247.                                 curwin->w_cursor.lnum = 1;
  3248.                             else
  3249.                                 ++curwin->w_cursor.lnum;
  3250.                         }
  3251.                         searchcmdlen = 0;
  3252.                         if (dosearch(c, cmd, FALSE, (long)1, FALSE, TRUE))
  3253.                             lnum = curwin->w_cursor.lnum;
  3254.                         curwin->w_cursor = pos;
  3255.                 
  3256.                         cmd += searchcmdlen;    /* adjust command string pointer */
  3257.                         break;
  3258.  
  3259.             default:
  3260.                         if (isdigit(*cmd))                /* absolute line number */
  3261.                             lnum = getdigits(&cmd);
  3262.         }
  3263.         
  3264.         while (*cmd == '-' || *cmd == '+')
  3265.         {
  3266.             if (lnum == MAXLNUM)
  3267.                 lnum = cursor_lnum;
  3268.             i = *cmd++;
  3269.             if (!isdigit(*cmd))    /* '+' is '+1', but '+0' is not '+1' */
  3270.                 n = 1;
  3271.             else 
  3272.                 n = getdigits(&cmd);
  3273.             if (i == '-')
  3274.                 lnum -= n;
  3275.             else
  3276.                 lnum += n;
  3277.         }
  3278.  
  3279.         cursor_lnum = lnum;
  3280.     } while (*cmd == '/' || *cmd == '?');
  3281.  
  3282. error:
  3283.     *ptr = cmd;
  3284.     return lnum;
  3285. }
  3286.  
  3287.  
  3288. #ifdef WEBB_COMPLETE
  3289. /*
  3290.  * Must parse the command line so far to work out what context we are in.
  3291.  * Completion can then be done based on that context.
  3292.  * This routine sets two global variables:
  3293.  *    char_u *expand_pattern --- The start of the pattern to be expanded within
  3294.  *                                the command line (ends at the cursor).
  3295.  *    int expand_context --- The type of thing to expand.  Will be one of:
  3296.  *      EXPAND_UNSUCCESSFUL --- Used somtimes when there is something illegal on
  3297.  *            the command line, like an unknown command.  Caller should beep.
  3298.  *      EXPAND_NOTHING --- Unrecognised context for completion, use char like a
  3299.  *            normal char, rather than for completion.  eg :s/^I/
  3300.  *      EXPAND_COMMANDS --- Cursor is still touching the command, so complete it.
  3301.  *      EXPAND_FILES --- After command with XFILE set, or after setting with
  3302.  *            P_EXPAND set.  eg :e ^I, :w>>^I
  3303.  *      EXPAND_DIRECTORIES --- In some cases this is used instead of the latter
  3304.  *            when we know only directories are of interest.  eg :set dir=^I
  3305.  *      EXPAND_SETTINGS --- Complete variable names.  eg :set d^I
  3306.  *      EXPAND_BOOL_SETTINGS --- Complete bollean variables only,  eg :set no^I
  3307.  *      EXPAND_TAGS --- Complete tags from the files in p_tags.  eg :ta a^I
  3308.  *
  3309.  * -- webb.
  3310.  */
  3311.     static void
  3312. set_expand_context(firstc, buff)
  3313.     int            firstc;     /* either ':', '/', or '?' */
  3314.     char_u        *buff;         /* buffer for command string */
  3315. {
  3316.     char_u        *nextcomm;
  3317.     char_u        old_char;
  3318.  
  3319.     old_char = cmdbuff[cmdpos];
  3320.     cmdbuff[cmdpos] = NUL;
  3321.     nextcomm = buff;
  3322.     while (nextcomm != NULL)
  3323.         nextcomm = set_one_cmd_context(firstc, nextcomm);
  3324.     cmdbuff[cmdpos] = old_char;
  3325. }
  3326.  
  3327. /*
  3328.  * This is all pretty much copied from DoOneCmd(), with all the extra stuff we
  3329.  * don't need/want deleted.  Maybe this could be done better if we didn't
  3330.  * repeat all this stuff.  The only problem is that they may not stay perfectly
  3331.  * compatible with each other, but then the command line syntax probably won't
  3332.  * change that much -- webb.
  3333.  */
  3334.     static char_u *
  3335. set_one_cmd_context(firstc, buff)
  3336.     int            firstc;     /* either ':', '/', or '?' */
  3337.     char_u        *buff;         /* buffer for command string */
  3338. {
  3339.     register char_u        *p;
  3340.     char_u                *cmd, *arg;
  3341.     int                 i;
  3342.     int                    cmdidx;
  3343.     int                    argt;
  3344.     char_u                delim;
  3345.     int                    forced = FALSE;
  3346.     int                    usefilter = FALSE;    /* filter instead of file name */
  3347.  
  3348.     expand_pattern = buff;
  3349.     if (firstc != ':')
  3350.     {
  3351.         expand_context = EXPAND_NOTHING;
  3352.         return NULL;
  3353.     }
  3354.     expand_context = EXPAND_COMMANDS;    /* Default until we get past command */
  3355.  
  3356. /*
  3357.  * 2. skip comment lines and leading space, colons or bars
  3358.  */
  3359.     for (cmd = buff; *cmd && strchr(" \t:|", *cmd) != NULL; cmd++)
  3360.         ;
  3361.     expand_pattern = cmd;
  3362.  
  3363.     if (*cmd == NUL)
  3364.         return NULL;
  3365.     if (*cmd == '"')        /* ignore comment lines */
  3366.     {
  3367.         expand_context = EXPAND_NOTHING;
  3368.         return NULL;
  3369.     }
  3370.  
  3371. /*
  3372.  * 3. parse a range specifier of the form: addr [,addr] [;addr] ..
  3373.  */
  3374.  
  3375.     --cmd;
  3376.     do
  3377.     {
  3378.         ++cmd;                            /* skip ',' or ';' */
  3379.         skipspace(&cmd);
  3380.         do
  3381.         {
  3382.             switch (*cmd)
  3383.             {
  3384.                 case '.':                         /* '.' - Cursor position */
  3385.                 case '$':                         /* '$' - last line */
  3386.                 case '%':                         /* '%' - all lines */
  3387.                     ++cmd;
  3388.                     break;
  3389.  
  3390.                 case '\'':                         /* ''' - mark */
  3391.                     if (*++cmd != NUL)
  3392.                         ++cmd;
  3393.                     break;
  3394.  
  3395.                 case '/':
  3396.                 case '?':                        /* '/' or '?' - search */
  3397.                     delim = *cmd++;
  3398.                     while (*cmd != NUL && *cmd != delim)
  3399.                         cmd++;
  3400.                     if (*cmd == delim)
  3401.                         cmd++;
  3402.                     break;
  3403.  
  3404.                 default:
  3405.                     while (isdigit((char)*cmd))
  3406.                         ++cmd;
  3407.                     break;
  3408.             }
  3409.             
  3410.             while (*cmd == '-' || *cmd == '+')
  3411.             {
  3412.                 cmd++;
  3413.                 while (isdigit(*cmd))
  3414.                     cmd++;
  3415.             }
  3416.         } while (*cmd == '/' || *cmd == '?');
  3417.     } while (*cmd == ',' || *cmd == ';');
  3418.  
  3419. /*
  3420.  * 4. parse command
  3421.  */
  3422.  
  3423.     skipspace(&cmd);
  3424.     expand_pattern = cmd;
  3425.     if (*cmd == NUL)
  3426.         return NULL;
  3427.     if (*cmd == '"')
  3428.     {
  3429.         expand_context = EXPAND_NOTHING;
  3430.         return NULL;
  3431.     }
  3432.  
  3433.     if (*cmd == '|' || *cmd == '\n')
  3434.         return cmd + 1;                    /* There's another command */
  3435.  
  3436.     /*
  3437.      * Isolate the command and search for it in the command table.
  3438.      * Exeptions:
  3439.      * - the 'k' command can directly be followed by any character.
  3440.      * - the 's' command can be followed directly by 'c', 'g' or 'r'
  3441.      */
  3442.     if (*cmd == 'k')
  3443.     {
  3444.         cmdidx = CMD_k;
  3445.         p = cmd + 1;
  3446.     }
  3447.     else
  3448.     {
  3449.         p = cmd;
  3450.         while (isalpha(*p) || *p == '*')    /* Allow * wild card */
  3451.             ++p;
  3452.         if (p == cmd && strchr("@!=><&~#", *p) != NULL)    /* non-alpha command */
  3453.             ++p;
  3454.         i = (int)(p - cmd);
  3455.  
  3456.         if (i == 0)
  3457.         {
  3458.             expand_context = EXPAND_UNSUCCESSFUL;
  3459.             return NULL;
  3460.         }
  3461.         for (cmdidx = 0; cmdidx < CMD_SIZE; ++cmdidx)
  3462.             if (STRNCMP(cmdnames[cmdidx].cmd_name, cmd, (size_t)i) == 0)
  3463.                 break;
  3464.     }
  3465.     if (p == cmdbuff + cmdpos)        /* We are still touching the command */
  3466.         return NULL;                /* So complete it */
  3467.  
  3468.     if (cmdidx == CMD_SIZE)
  3469.     {
  3470.         if (*cmd == 's' && strchr("cgr", cmd[1]) != NULL)
  3471.         {
  3472.             cmdidx = CMD_substitute;
  3473.             p = cmd + 1;
  3474.         }
  3475.         else
  3476.         {
  3477.             /* Not still touching the command and it was an illegal command */
  3478.             expand_context = EXPAND_UNSUCCESSFUL;
  3479.             return NULL;
  3480.         }
  3481.     }
  3482.  
  3483.     expand_context = EXPAND_NOTHING; /* Default now that we're past command */
  3484.  
  3485.     if (*p == '!')                    /* forced commands */
  3486.     {
  3487.         forced = TRUE;
  3488.         ++p;
  3489.     }
  3490.  
  3491. /*
  3492.  * 5. parse arguments
  3493.  */
  3494.     argt = cmdnames[cmdidx].cmd_argt;
  3495.  
  3496.     arg = p;                        /* remember start of argument */
  3497.     skipspace(&arg);
  3498.  
  3499.     if (cmdidx == CMD_write)
  3500.     {
  3501.         if (*arg == '>')                        /* append */
  3502.         {
  3503.             if (*++arg == '>')                /* It should be */
  3504.                 ++arg;
  3505.             skipspace(&arg);
  3506.         }
  3507.         else if (*arg == '!')                    /* :w !filter */
  3508.         {
  3509.             ++arg;
  3510.             usefilter = TRUE;
  3511.         }
  3512.     }
  3513.  
  3514.     if (cmdidx == CMD_read)
  3515.     {
  3516.         usefilter = forced;                    /* :r! filter if forced */
  3517.         if (*arg == '!')                        /* :r !filter */
  3518.         {
  3519.             ++arg;
  3520.             usefilter = TRUE;
  3521.         }
  3522.     }
  3523.  
  3524.     if (cmdidx == CMD_lshift || cmdidx == CMD_rshift)
  3525.     {
  3526.         while (*arg == *cmd)        /* allow any number of '>' or '<' */
  3527.             ++arg;
  3528.         skipspace(&arg);
  3529.     }
  3530.  
  3531.     /*
  3532.      * Check for '|' to separate commands and '"' to start comments.
  3533.      * Don't do this for ":read !cmd" and ":write !cmd".
  3534.      */
  3535.     if ((argt & TRLBAR) && !usefilter)
  3536.     {
  3537.         p = arg;
  3538.         while (*p)
  3539.         {
  3540.             if (*p == Ctrl('V'))
  3541.             {
  3542.                 if (p[1] != NUL)
  3543.                     ++p;
  3544.             }
  3545.             else if ((*p == '"' && !(argt & NOTRLCOM)) || *p == '|' || *p == '\n')
  3546.             {
  3547.                 if (*(p - 1) != '\\')
  3548.                 {
  3549.                     if (*p == '|' || *p == '\n')
  3550.                         return p + 1;
  3551.                     return NULL;    /* It's a comment */
  3552.                 }
  3553.             }
  3554.             ++p;
  3555.         }
  3556.     }
  3557.  
  3558.     if (!(argt & EXTRA) && strchr("|\"", *arg) == NULL)    /* no arguments allowed */
  3559.         return NULL;
  3560.  
  3561.     /* Find start of last argument (argument just before cursor): */
  3562.     p = cmdbuff + cmdpos;
  3563.     while (p != arg && *p != ' ' && *p != TAB)
  3564.         p--;
  3565.     if (*p == ' ' || *p == TAB)
  3566.         p++;
  3567.     expand_pattern = p;
  3568.  
  3569.     if (argt & XFILE)
  3570.         expand_context = EXPAND_FILES;
  3571.  
  3572. /*
  3573.  * 6. switch on command name
  3574.  */
  3575.     switch (cmdidx)
  3576.     {
  3577.         case CMD_cd:
  3578.         case CMD_chdir:
  3579.             expand_context = EXPAND_DIRECTORIES;
  3580.             break;
  3581.         case CMD_buffer:
  3582.         case CMD_wnext:
  3583.         case CMD_args:            /* args now takes arguments like :next */
  3584.         case CMD_next:
  3585.         case CMD_snext:
  3586.         case CMD_split:
  3587.         case CMD_new:
  3588.         case CMD_edit:
  3589.         case CMD_ex:
  3590.         case CMD_visual:
  3591.             for (p = arg; *p; ++p)
  3592.             {
  3593.                 if (*p == '\\' && p[1])
  3594.                     ++p;
  3595.                 else if (*p == '|' || *p == '\n')
  3596.                     return p + 1;
  3597.             }
  3598.             break;
  3599.         case CMD_global:
  3600.         case CMD_vglobal:
  3601.             delim = *arg;             /* get the delimiter */
  3602.             if (delim)
  3603.                 ++arg;                /* skip delimiter if there is one */
  3604.  
  3605.             while (arg[0] != NUL && arg[0] != delim)
  3606.             {
  3607.                 if (arg[0] == '\\' && arg[1] != NUL)
  3608.                     ++arg;
  3609.                 ++arg;
  3610.             }
  3611.             if (arg[0] != NUL)
  3612.                 return arg + 1;
  3613.             break;
  3614.         case CMD_and:
  3615.         case CMD_substitute:
  3616.             delim = *arg;
  3617.             if (delim)
  3618.                 ++arg;
  3619.             for (i = 0; i < 2; i++, arg++)
  3620.                 while (arg[0] != NUL && arg[0] != delim)
  3621.                 {
  3622.                     if (arg[0] == '\\' && arg[1] != NUL)
  3623.                         ++arg;
  3624.                     ++arg;
  3625.                 }
  3626.             while (arg[0] != NUL && strchr("|\"#", arg[0]) == NULL)
  3627.                 ++arg;
  3628.             if (arg[0] != NUL)
  3629.                 return arg;
  3630.             break;
  3631.         case CMD_set:
  3632.             set_context_in_set_cmd(arg);
  3633.             break;
  3634.         case CMD_tag:
  3635.             expand_context = EXPAND_TAGS;
  3636.             expand_pattern = arg;
  3637.             break;
  3638.         default:
  3639.             break;
  3640.     }
  3641.     return NULL;
  3642. }
  3643.  
  3644. /*
  3645.  * Do the expansion based on the global variables expand_context and
  3646.  * expand_pattern -- webb.
  3647.  */
  3648.     static int
  3649. ExpandFromContext(pat, num_file, file, files_only, list_notfound)
  3650.     char_u *pat;
  3651.     int *num_file;
  3652.     char_u ***file;
  3653.     int files_only;
  3654.     int list_notfound;
  3655. {
  3656.     regexp    *prog;
  3657.     int        cmdidx;
  3658.     int        count;
  3659.     int        ret;
  3660.     int        i;
  3661.  
  3662.     if (!expand_interactively || expand_context == EXPAND_FILES)
  3663.         return ExpandWildCards(1, &pat, num_file, file, files_only, list_notfound);
  3664.     else if (expand_context == EXPAND_DIRECTORIES)
  3665.     {
  3666.         if (ExpandWildCards(1, &pat, num_file, file, files_only, list_notfound)
  3667.                                                                     == FAIL)
  3668.             return FAIL;
  3669.         count = 0;
  3670.         for (i = 0; i < *num_file; i++)
  3671.             if (isdir((*file)[i]))
  3672.                 (*file)[count++] = (*file)[i];
  3673.             else
  3674.                 free((*file)[i]);
  3675.         if (count == 0)
  3676.         {
  3677.             free(*file);
  3678.             *file = (char_u **)"";
  3679.             *num_file = -1;
  3680.             return FAIL;
  3681.         }
  3682.         *num_file = count;
  3683.         return OK;
  3684.     }
  3685.     *file = (char_u **)"";
  3686.     *num_file = 0;
  3687.     ret = OK;
  3688.     reg_ic = FALSE;
  3689.     reg_magic = p_magic;
  3690.     prog = regcomp(pat);
  3691.     if (prog == NULL)
  3692.         return FAIL;
  3693.     if (expand_context == EXPAND_COMMANDS)
  3694.     {
  3695.         /* Count the matches: */
  3696.         count = 0;
  3697.         for (cmdidx = 0; cmdidx < CMD_SIZE; cmdidx++)
  3698.             if (regexec(prog, cmdnames[cmdidx].cmd_name, TRUE))
  3699.                 count++;
  3700.         if (count == 0
  3701.           || (*file = (char_u **) alloc((int)(count * sizeof(char_u *)))) == NULL)
  3702.             ret = FAIL;
  3703.         else
  3704.         {
  3705.             *num_file = count;
  3706.             count = 0;
  3707.             for (cmdidx = 0; cmdidx < CMD_SIZE; cmdidx++)
  3708.                 if (regexec(prog, cmdnames[cmdidx].cmd_name, TRUE))
  3709.                     (*file)[count++] = strsave(cmdnames[cmdidx].cmd_name);
  3710.         }
  3711.     }
  3712.     else if (expand_context == EXPAND_SETTINGS
  3713.       || expand_context == EXPAND_BOOL_SETTINGS)
  3714.         ret = ExpandSettings(prog, num_file, file);
  3715.     else if (expand_context == EXPAND_TAGS)
  3716.         ret = ExpandTags(prog, num_file, file);
  3717.     else
  3718.         ret = FAIL;
  3719.     
  3720.     free(prog);
  3721.     return ret;
  3722. }
  3723. #endif /* WEBB_COMPLETE */
  3724.